Advertisement

Dynamic Sprite Framework with PHP

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

In this Nettuts+ PLUS tutorial, you will learn how to create a dynamic "Image Sprite Framework" from an icon set of your choosing. The framework will consist of the sprite image, a sprite stylesheet whose class names and properties correspond to the icons within our sprite image, and an HTML preview page which we can use a quick reference guide for the framework.

The "Dynamic Sprite Framework" will enable you to use any icon from the sprite by specifying its relative class name which will directly correspond to the icon's file name.

By the end of this tutorial, you should feel comfortable creating dynamic image sprites on your own and should be able to implement and take full advantage of the many benefits this system provides.

Scroll to the bottom to find the full Premium screencast!


Gathering information

In order to create an image sprite we'll first need to gather some basic information. We'll need to know the following, for starters:

  • The directory containing the icons we'd like to use for the sprite - with a trailing slash at the end
  • The width of the icons
  • The height of the icons
  • The x offset we'd like for each icon - this will be their horizontal spacing
  • The y offset we'd like for each icon - this is be their vertical spacing
  • The image type for the icons - png, gif or jpg
  • How many icons we'd like to display per row in our sprite
  • The target directory for our sprite - with a trailing slash at the end
  • The target name for our new sprite image

We are going to build an HTML page with a simple FORM to collect this data. Let's have a look at this FORM:

 
<!doctype html> 
<html lang="en"> 
 
<head> 
	 <title>Sprite Builder</title> 
	 <meta charset="utf-8"> 
 
     <link rel="stylesheet" type="text/css" href="main.css"> 
</head> 
 
    <body> 
 
         <div id="content"> 
 
               <form action="sprite_builder.php" method="POST"> 
                    <fieldset> 
                         <legend>Sprite Builder</legend> 
 
                         <label for="icon_source" class="label">Image Directory:</label> 
                         <input id="icon_source" class="ui-corner-all" type="text" name="icon_source" value=""> 
 
                         <label for="icon_width" class="label">Icon Width:</label> 
                         <input id="icon_width" class="ui-corner-all" type="text" name="icon_width" value=""> 
 
                         <label for="icon_height" class="label">Icon Height:</label> 
                         <input id="icon_height" class="ui-corner-all" type="text" name="icon_height" value=""> 
 
                         <label for="x_offset" class="label">Icon X Offset:</label> 
                         <input id="icon_width" class="ui-corner-all" type="text" name="x_offset" value=""> 
 
                         <label for="y_offset" class="label">Icon Y Offset:</label> 
                         <input id="y_offset" class="ui-corner-all" type="text" name="y_offset" value=""> 
 
                         <div class="radio"> 
                              <label for="icon_type" class="label">Image Type:</label> 
                              <div class="radioWrap"><input type="radio" name="icon_type[]" value="png">PNG</div> 
                              <div class="radioWrap"><input type="radio" name="icon_type[]" value="jpg">JPEG</div> 
                              <div class="radioWrap"><input type="radio" name="icon_type[]" value="gif">GIF</div> 
                         </div><!-- DIV.radio --> 
 
 
                         <label for="icons_per_row" class="label">Icons per Row:</label> 
                         <input id="icons_per_row" class="ui-corner-all" type="text" name="icons_per_row" value=""> 
 
                         <label for="target_directory" class="label">Target Directory:</label> 
                         <input id="target_directory" class="ui-corner-all" type="text" name="target_directory" value=""> 
 
                         <label for="target_name" class="label">Target Name:</label> 
                         <input id="target_name" class="ui-corner-all" type="text" name="target_name" value=""> 
 
                         <button type="submit">Submit</button> 
 
                    </fieldset> 
               </form> 
 
          </div> 
 
    </body> 
 
</html>

As you can see, above, we've built a simple HTML5 page with a FORM.

The FORM will POST its results to our sprite_builder.php page.

The FORM itself has nine fields for gathering the information we need:

  • icon_source
  • icon_width
  • icon_height
  • x_offset
  • y_offset
  • icon_type
  • icons_per_row
  • target_directory
  • target_name

Prepping our data


1. Checking the POST array

Now that we have our FORM in place we'll be able to collect all the data we need...

In our PHP, we'll start by checking to see if all the FORM FIELDS have been submitted with a value.

If any of the VALUES aren't set, we'll simply redirect the user back to the FORM page.

Please note that in a production environment you will want to nail down / secure this FORM some more and provide some feedback to the user.

Let's create a new php file named 'sprite_builder.php' now and check to see that all the FORM FIELDS we specified have been submitted with a VALUE.

 
<?php 
	if (isset($_POST['icon_source']) && isset($_POST['icon_width']) && isset($_POST['icon_height']) && isset($_POST['icon_type']) && isset($_POST['icons_per_row']) && isset($_POST['target_directory']) && isset($_POST['target_name'])) 
	{ 
 
     } 
     else 
     { 
          header('Location: http://localhost/Sprite/index.html'); 
     }

2. Sanitization

If the above condition is met, meaning all the items in the POST array have a value, we'll sanitize and prep these VALUES a bit.

Let's create a function to prep our data for us.

 
function prep($post) 
{ 
     $post = htmlspecialchars(trim($post)); 
     return $post; 
}

The prep() function does the following:

  • htmlspecialchars - All data passed to the 'prep' function will have 'key' HTML tags any symbols within it converted to HTML entities
  • trim - We then trim all of the whitespace from the beginning and end of the string

3. Building an array with our prepped data

We'll be prepping the data from our POST array while building a new 'sprite' array with those prepped values.

First, we'll initialize our 'sprite' array.

Then, we'll begin iterating through all of the array_keys for the POST array.

While iterating through the POST array keys, we'll check that each POST VALUE is a string.

If the VALUE is a string, we'll add it to our 'sprite' array using the array key as it's name within the sprite array.

After this foreach loop, we'll store our 'output path' in the 'sprite' array as well.

We'll define the 'output_path' by concatenating the 'target_directory' var with the 'target_name' var.

Please note that we won't be adding a file extension here, we'll define that later on.

Since the 'icon_type' FIELD is an array, we'll iterate through it to get the submitted VALUE and then run that value through our prep() function and add it to our 'sprite' array.

Next, we'll initialize an 'icon_name' array which will be contained within our sprite array.

Note: We'll build the 'icon_name' array once we've opened up and are reading the target directory...

 
<?php 
 
     function prep($post) 
     { 
          $post = htmlspecialchars(trim($post)); 
          return $post; 
     } 
 
	if (isset($_POST['icon_source']) && isset($_POST['icon_width']) && isset($_POST['icon_height']) && isset($_POST['icon_type']) && isset($_POST['icons_per_row']) && isset($_POST['target_directory']) && isset($_POST['target_name'])) 
	{ 
          $sprite = array(); 
 
          $array_key = array_keys($_POST); 
          foreach($array_key as $key) 
          { 
               if(is_string($_POST[$key])) 
               { 
                    $sprite[$key] = prep($_POST[$key]); 
               } 
          } 
 
          $sprite['path'] = $sprite['target_directory'].$sprite['target_name']; 
 
          foreach($_POST['icon_type'] as $key => $value) 
          { 
               $sprite['icon_type'] = prep($value); 
          } 
 
          $sprite['icon_name'] = array(); 
     } 
     else 
     { 
          header('Location: http://localhost/Sprite/index.html'); 
     }

4. Retrieving and adding valid image names to our array

Now that we've built an array which contains all of the values from the POST array, we'll build an array of image names.

Here's what we'll be doing in the next few lines of code:

  • We'll start by opening up the icon directory specified in our FORM.
  • Then, we'll set the total number of images to zero and as we read this directory, adding image names to our array, we'll increment this value for each one. This will give us the total number of images in our directory / array.
  • Next, we'll read the directory using a simple while loop
  • While reading the directory, we will get the path info for each file and check it's extension. We'll convert the extension to lowercase and compare it against the 'image_type' specified in the Sprite Builder FORM
  • If the extensions match, we will use path_info, again, to get the file name of the image and add it to our 'icon_name' array.
  • We'll then increment our icon total by 1.
  • Once we're finished reading through the contents of this directory, we'll sort the 'icon_name' array alphabetically and add the icon total to our 'sprite' array.
 
$sprite_directory = opendir( $sprite['icon_source'] ); 
$image_total = 0; 
 
while ($file_name = readdir( $sprite_directory )) 
{ 
     $path_info = pathinfo( $file_name ); 
 
     if ( strtolower($path_info['extension']) === $sprite['icon_type'] ) 
     { 
          $sprite['icon_name'][] = $path_info['filename']; 
          $image_total++; 
     } 
} 
 
sort($sprite['icon_name']); 
$sprite['icon_total'] = $image_total;

With the 'sprite' array complete, we can now move on to creating our 'sprite_builder' object.


The Sprite Builder Object


1. Object overview

In order to do the things we'd like to do in an orderly and efficient manner, we are going to build an Object.

This object will do three things:

  • Create an image sprite
  • Create a CSS file for the sprite image with classes and background-positions corresponding to the individual icon names and locations within the sprite
  • Create an HTML preview page for the sprite and it's relevant CSS rules

2. Building our Object

The first thing we'll do is define our Object/Class and it's property types.

Since we are only working with one object and we don't need to access any of it's properties outside of the class we'll make them all private.

 
class Sprite_builder 
{ 
     private $icon_source; 
     private $icon_width; 
     private $icon_height; 
     private $icons_per_row; 
     private $target_directory; 
     private $target_name; 
     private $path; 
     private $icon_type; 
     private $icon_total; 
     private $icon_name; 
     private $x_offset; 
     private $y_offset; 
}

3. The class Constructor

Now, we'll create our Class Constructor.

Within our constructor, we'll define each of our object's properties using the corresponding values in our sprite array.

This will make all of these properties available to every method within our class.

 
class Sprite_builder 
{ 
     private $icon_source; 
     private $icon_width; 
     private $icon_height; 
     private $icons_per_row; 
     private $target_directory; 
     private $target_name; 
     private $path; 
     private $icon_type; 
     private $icon_total; 
     private $icon_name; 
     private $x_offset; 
     private $y_offset; 
 
     function Sprite_builder($sprite) 
     { 
          $this->icon_source= $sprite['icon_source']; 
          $this->icon_width= $sprite['icon_width']; 
          $this->icon_height= $sprite['icon_height']; 
          $this->icons_per_row= $sprite['icons_per_row']; 
          $this->target_directory= $sprite['target_directory']; 
          $this->target_name= $sprite['target_name']; 
          $this->path= $sprite['path']; 
          $this->icon_type= $sprite['icon_type']; 
          $this->icon_total= $sprite['icon_total']; 
          $this->icon_name= $sprite['icon_name']; 
          $this->x_offset= $sprite['x_offset']; 
          $this->y_offset= $sprite['y_offset']; 
     } 
}

Worth repeating: We are defining each property with it's corresponding value in the sprite array: source directory, icon width, height, x offset, y offset etc...


Sprite Builder Method One - Creating the Sprite


1. Method overview

Our first method will be the create_sprite() function.

This method will create a new sprite comprised of all of the valid images specified in our 'image_name' array.

Here is a general overview of the steps we'll take to achieve this:

  • First, we'll define the x_position and y_position properties. These properties will determine the icon's position along the x and y axis respectively. We will use the 'x_offset' and 'y_offset' settings specified in our Sprite Builder FORM.
  • Next, we will set our 'icon_per_row_count' to 0. We'll increment this by 1 for each icon we add to the sprite
  • Now, using the data we have available from the Sprite Builder FORM, we'll calculate the total height and width for the new image sprite
  • With the sprite's dimensions set, we'll create the 'basic' image:
    • First, we'll create a 'generic' image using the imagecreatetruecolor command. We'll specify it's dimensions with the results from our height and width calculations mentioned above
    • Next, we'll configure this image to retain transparency. We'll use the imagesavealpha command to do so. This will set a 'save transparency' flag for this image.
    • Having flagged our image for transparency, we'll now define it's color and transparency values using the imagecolorallocatealpha command. We'll set all the RGB channel values to 0 and the transparency channel to 127 which is full transparency
    • Lastly, we'll 'flood' fill the image with our 'imagecolorallocatealpha' values using the imagefill command
  • The sprite image is now ready to go. Our next step is to begin iterating through our 'icon_name' array. As we iterate through that array we'll do the following:
    • Depending on the image type specified in our Sprite Builder FORM, we'll create a new image for each icon using one of the following commands, imagecreatefrompng, imagecreatefromgif or imagecreatefromjpeg. We'll concatenate the 'icon_name' with the 'icon_type' property in order to specify the image source.
    • Now, using the imagecopy command, we'll copy this icon onto our sprite. We'll offset it using our 'x_position' and 'y_position' properties and we'll set it's dimensions using our 'icon_width' and 'icon_height' properties.
    • Having added the icon to our sprite, we'll now increment our 'icon_per_row_count' by 1
    • Next, we'll need to determine if we've reached the 'icons_per_row' limit we specified in the Sprite Builder FORM. If we have, we'll do the following:
      • First, we'll need to recalculate the icons position vertically as we're starting a new row. We'll do this by taking it's current 'y_position' and adding the 'icon_height' and 'y_offset' to it.
      • Next, we'll reset the 'x_position' back to it's default setting which is the 'x_offset' property defined in our Sprite Builder FORM. Thus, the next icon will be copied to the far left side of our sprite.
      • Now, we'll reset our 'icon_per_row_count' to 0 as there are no images on this row yet
      • Lastly, we'll increment our 'row_count' by 1 as we've just completed a row
    • If the 'icon_per_row_count' count does not match our 'icons_per_row' limit, we'll only need to recalculate the 'x_position' so that the next icon is positioned further down along the x-axis
    • Now that this 'icon' has been copied to our sprite, we can destroy it using the imagedestroy command.
  • We'll terminate our foreach loop here
  • Having iterated through all of our 'icons' and copied each one over to the sprite, we'll go ahead and output the sprite image to a file. First, though, we'll check the image type again so that we use the appropriate method to output the sprite. We'll be using either the imagepng, imagegif or imagejpeg command to do this.
  • With our sprite image saved to a file, we can go ahead and destroy the GD image we were working by using the imagedestroy command.
 
     function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
          imagesavealpha($this->new_sprite, true); 
 
          $this->new_sprite_opacity= imagecolorallocatealpha($this->new_sprite, 0, 0, 0, 127); 
          imagefill($this->new_sprite, 0, 0, $this->new_sprite_opacity); 
 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
 
               imagedestroy($this->icon); 
          } 
 
          if($this->icon_type == 'png') 
          { 
               imagepng($this->new_sprite, "{$this->path}.{$this->icon_type}"); 
          } 
          else if($this->icon_type == 'gif') 
          { 
               imagegif($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
          else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
          { 
               imagejpeg($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
          imagedestroy($this->new_sprite); 
     }

2. Base settings

Before we take a closer look at this method, we'll need to define a few settings first.

  • x_position - As we iterate through the 'icon_names' we'll have to calculate the x offset for each new icon within the row. We will start by using the 'x_offset' property which was defined in our Sprite Builder FORM.
  • y_position - We will use the 'y_offset' property, which was also defined in our Sprite Builder FORM, to set the icon's initial position along the y-axis. Once we reach the limit of icons for 'this' row, we'll recalculate the 'y_position' in order to move the next and following icons down 1 row.
  • icon_per_row_count - Initially, this will be set to 0. As we iterate through our 'icon_names' and add them to the sprite we'll increment this by 1 for each icon.
  • sprite_width - Here, we'll calculate the width of the sprite image using some of the values we collected in our Sprite Builder FORM
  • sprite_height - Additionally, we'll also calculate the sprite image's height using some of the same values we collected in the FORM
 
function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
     }

3. Base calculations

WIDTH - In order to determine the Sprite image's width, we'll add the width of each icon to it's x_offset specified in the Sprite Builder FORM.

Then, we will multiply this value by our total number of icons per row limit we specified in the Sprite Builder FORM.

Lastly, we'll add the x_offset to this this integer. This will give the Sprite a margin along the right side, or, if you will, pad the images in along the right side of the sprite.

HEIGHT - In order to calculate the Sprite image's height, we'll add the height of each icon to it's y_offset specified in the Sprite Builder FORM.

Then, we'll multiply this by the total number of icons we have, divided by how many icons we have per row rounded up to the next integer using the ceil method.

Lastly, we'll add the y_offset to this this integer to give the Sprite a margin along the bottom, or, if you will, 'pad' the images in along the bottom of the sprite.

4. Creating the image with transparency

With our sprites dimensions defined we can now go ahead and create the actual image.

To do so, we'll be using the imagecreatetruecolor command.

This command takes two arguments, width and height. We'll use the 'sprite_width' and 'sprite_height' values we just calculated.

 
function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
     }

Our next step will be to flag this image for transparency so that it will retain all of its alpha channel information.

We do this using the imagesavealpha command.

This command takes two arguments, the image source and a Boolean value which determines whether or not you'd like to save transparency for this image.

We'll specify true for the second parameter.

 
function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
          imagesavealpha($this->new_sprite, true); 
     }

5. Defining our Sprite's color and transparency

With our image created and flagged for transparency, we'll now define its color and transparency values.

We'll do this by using the imagecolorallocatealpha command.

This command takes five arguments, image source, red channel, green channel, blue channel and alpha channel (transparency).

We'll specify our image source and set all of the color channels to 0 while setting the alpha channel, which is used for transparency, to 127 which is the maximum setting or fully transparent.

 
function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
          imagesavealpha($this->new_sprite, true); 
 
          $this->new_sprite_opacity= imagecolorallocatealpha($this->new_sprite, 0, 0, 0, 127); 
     }

Having defined our sprites color and transparency we now flood fill the image with these values using the imagefill command.

This command takes four arguments, image source, the x coordinate to start our fill at, the y coordinate to start our fill at and the color / transparency settings which we specified in the previous step.

We'll start our fill at position 0,0 in order to fill the entire image.

 
function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
          imagesavealpha($this->new_sprite, true); 
 
          $this->new_sprite_opacity= imagecolorallocatealpha($this->new_sprite, 0, 0, 0, 127); 
          imagefill($this->new_sprite, 0, 0, $this->new_sprite_opacity); 
     }

6. Iterating through our 'icon_names'

Now that we created a base image for our Sprite, with transparency, we need to iterate through the icons within our 'icon_names' array, fetch their corresponding images and copy them, individually, to our sprite.

Here is a general outline of the steps we will take within our foreach loop:

  • Loop through all of the 'icon_names' within the 'icon_name' array using a foreach statement
    • Determine the file type of the icon and create a new image image for it using the appropriate 'imagecreatefrom' method
    • Use the imagecopy command to copy the icon over to our sprite while specifying it's offset within the sprite using the 'x_position' and 'y_position' properties
    • Increment our 'icon_per_row_count' by 1 as we've just added a new icon to the Sprite
    • Determine if we have reached the 'icons_per_row' limit by comparing the value of our 'icons_per_row' limit to that of the current 'icon_per_row_count'
      • If the number of icons we iterated through so far, the 'icon_per_row_count', matches the 'icons_per_row' limit, we'll need to move down a row by recalculating our x_position and y_position
        • We'll adjust the y_position so that we'll be copying our icons over to the 'next' row of the sprite
        • We'll 'reset' the x_position back to the start of the new row - the far left side of the sprite
      • Additionally, we will reset our 'icon_per_row_count' to 0 and increment our 'row_count' by 1
    • If we haven't reached the 'icons_per_row' limit, we'll simply recalculate the 'x_position' property so that we'll be copying the next icon further down along the x-axis
  • Terminate the foreach loop
  • Now, we'll use the imagedestroy command to destroy the current 'icon' we are working with in GD as we won't need it anymore

Here's how the code will look, thus far, beginning with the foreach loop:

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
 
               imagedestroy($this->icon); 
          }

Within the loop, you'll see that we begin by determining the image type.

Then, we create the appropriate image for the 'icon_name' we are working with.

We fetch the actual image by concatenating the 'icon_source' property with the 'icon_name' and 'icon_type' properties.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
          }

You'll notice above that we are using curly brackets.

This is known as the complex curly syntax.

When defining a string with double quotes, you can wrap your variables in curly braces which separates them form other characters in the string.

This allows you to use your variable name next to any character while keeping the var separate.

It's also more readable than regular concatenation and especially useful when dealing with CSS rules where letters, such as 'px' or 'em', will immediatly follow a property value.

For example: background-position: {$foo}px {$bar}px.

Next, we'll copy this icon onto our sprite image using the imagecopy command.

The imagecopy command takes eight parameters, destination image, source image, x coordinate on the target, y coordinate on the target, x coordinate of the source image, y coordinate of the source image, width of the source image and height of the source image.

We'll specify our 'new_sprite' as the target for the copy.

We'll use the 'x_position' and 'y_position' properties, respectively, to determine the icons placement on the sprite.

We'll set the source coordinates, for our icon, to 0, 0 so that we copy over the entire icon.

Lastly, we'll use the 'icon_width' and 'icon_'height' properties, respectively, to set the icons dimensions within the Sprite.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
          }

Having copied the icon over to the Sprite, we'll increment our 'icon_per_row_count' by 1

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
          }

Now, we'll check to see if we've reached the max image limit along for x-axis (horizontally).

We do this by comparing the image row count to the 'images_per_row' limit specified in our 'Sprite Builder' FORM.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
               } 
               else 
               { 
               } 
 
          }

If the values match, we have reached the limit for icons on this row. We'll need to do the following:

  • Recalculate the y_position for our icons in order to move them down to a new row on the sprite image.
  • Reset the x_position for the next icon rule to it's default position which is the beginning / left side of our sprite image
  • Reset our 'icon_per_row_count' to 0 as there are no images on this row yet
  • Increment our 'row_count' by 1 as we have now moved down a row

To calculate the new position for our icons along the y-axis, we'll need to take the current y_position, add the y_offset to it and then add the icons height to it as well.

This will effectively move the image down to a new row while maintaining the y_offset specified in the Sprite Builder FORM.

Additionally, we'll set our 'x_position' property equal to our 'x_offset' property again

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
               } 
          }

If the 'icon_per_row_count' and 'icons_per_row' values don't match, we have not reached the end of the icons on this row and we'll just need to recalculate the 'x_position' property in order to move the next icon further down along the x-axis.

We do this by taking the current x_position and adding the 'x_offset' property to it and then adding the icons width to it as well.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
          }

With the icons now added to the sprite, we can go ahead and destroy the icon we are working with in GD and terminate the foreach loop.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
 
               imagedestroy($this->icon); 
          }

7. Finishing up

With all of the icons finally copied over to the Sprite, the last thing we'll need to do is output it to an image file.

Again, we'll do this according to the image's file type.

Well be using either the imagepng, imagegif, or imagejpeg command respectively.

Once we've output the Sprite to a file we can destroy the 'sprite' image we've been working with in GD.

 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
 
               imagedestroy($this->icon); 
          } 
 
          if($this->icon_type == 'png') 
          { 
               imagepng($this->new_sprite, "{$this->path}.{$this->icon_type}"); 
          } 
          else if($this->icon_type == 'gif') 
          { 
               imagegif($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
          else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
          { 
               imagejpeg($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
 
          imagedestroy($this->new_sprite);

7. The full method

Here is the full create_image() method in its entirety:

 
     function create_image() 
     { 
          $this->x_position = $this->x_offset; 
          $this->y_position = $this->y_offset; 
 
          $this->icon_per_row_count = 0; 
 
          $this->sprite_width = (($this->icon_width + $this->x_offset) * $this->icons_per_row) + $this->x_offset; 
          $this->sprite_height = (($this->icon_height + $this->y_offset) * ceil($this->icon_total / $this->icons_per_row)) + $this->y_offset; 
 
          $this->new_sprite = imagecreatetruecolor($this->sprite_width, $this->sprite_height); 
          imagesavealpha($this->new_sprite, true); 
 
          $this->new_sprite_opacity= imagecolorallocatealpha($this->new_sprite, 0, 0, 0, 127); 
          imagefill($this->new_sprite, 0, 0, $this->new_sprite_opacity); 
 
          foreach ($this->icon_name as $image) 
          { 
               if($this->icon_type == 'png') 
               { 
                    $this->icon = imagecreatefrompng("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'gif') 
               { 
                    $this->icon = imagecreatefromgif("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
               else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
               { 
                    $this->icon = imagecreatefromjpeg("{$this->icon_source}{$image}.{$this->icon_type}"); 
               } 
 
               imagecopy($this->new_sprite, $this->icon, $this->x_position, $this->y_position, 0, 0, $this->icon_width, $this->icon_height); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position + $this->icon_width + $this->y_offset; 
                    $this->x_position = $this->x_offset; 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position + $this->icon_width + $this->x_offset; 
               } 
 
               imagedestroy($this->icon); 
          } 
 
          if($this->icon_type == 'png') 
          { 
               imagepng($this->new_sprite, "{$this->path}.{$this->icon_type}"); 
          } 
          else if($this->icon_type == 'gif') 
          { 
               imagegif($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
          else if($this->icon_type == 'jpg' || $this->icon_type == 'jpeg') 
          { 
               imagejpeg($this->new_sprite, $this->path.'.'.$this->icon_type); 
          } 
          imagedestroy($this->new_sprite); 
     }

Sprite Builder Method Two - Creating the Stylesheet


1. Method overview

Our second method will be the create_stylesheet() function. This method will output a new stylesheet for our image sprite.

Our first selector will be a class selector which will match the 'target_name' specified in our Sprite Builder form.

We'll convert this 'target_name' to lower case as it's as class names should always start with a lower case letter.

This class will only have one property, background-image, and the value of that property will be the sprite image which we just created.

We will iterate through our 'icon_name' array and create a new rule for each 'icon_name' using that name as a class selector.

Each of these rules will have only one property, background-position, and the value of that property will be relative to the icon's dimensions, x/y offsets and how many icons we are displaying per row.

The CSS background-position property will correspond to the icon's x/y position within the sprite image.

2. Base settings

Before we go any further we're going to need to define a few settings within this method.

  • icon_per_row_count - Initially, this will be set to 0. As we iterate through our 'icon_names' and add them to the sprite, we'll increment this by 1 for each icon.
  • row_count - Similar to 'icon_per_row_count', we'll need to keep track of which row we are on. We'll increment the row count by 1 every time we reach the 'icons_per_row' limit in our foreach loop and move down a row
  • x_position - As we iterate through the 'icon_names' we'll have to calculate the background position for each icon within the sprite. This will server as the 'x' position within the CSS rule.
  • y_position - Similar to 'x_position', once we reach the 'icons_per_row' limit in our loop we will need to calculate the new 'y' position for our class rule.
 
function create_stylesheet() 
{ 
     $this->icon_per_row_count = 0; 
     $this->row_count = 0; 
     $this->x_position = ($this->x_offset * (-1)); 
     $this->y_position = ($this->y_offset * (-1)); 
}

3. Base X/Y calculations

In order to determine our base x/y coordinates, we are going to take our x_offset setting and our y_offset setting, which were specified in the Sprite Builder FORM, and multiply each of them by negative 1.

Position 0px 0px on the sprite itself will be the top left most corner of the image.

We need to move the image 'up' and to the 'left' - hence the negative values.

Additionally, since each icon is offset vertically and horizontally by the x and y offsets specified in our Sprite Builder FORM, we will use those settings to set our background-position accordingly.

4. Creating the stylesheet

Now that we have our base settings and calculations out of the way we can go ahead and create our stylesheet.

In PHP, this can be done with the fopen command in 'a' mode which will create the file if it doesn't already exist and write any new data to the end of the file.

We will concatenate our 'path' setting from the Sprite Builder FORM with the file extension for stylesheets which is 'css'.

 
function create_stylesheet() 
{ 
     $this->icon_per_row_count = 0; 
     $this->row_count = 0; 
     $this->x_position = ($this->x_offset * (-1)); 
     $this->y_position = ($this->y_offset * (-1)); 
 
     $create_css = fopen($this->path.'.css', 'a'); 
}

5. Writing our base CSS rule

With the new css file created and open, we can now define our base CSS rule.

This rule will be a sort of meta rule for all of our sprite images.

Its only property will be 'background-image'. This class will be used in conjunction with the class rules for each individual icon within our sprite.

We will use the 'target_name' specified in our Sprite Builder FORM, converted to lowercase, as our base class. We'll only need to define the background-image property as the new sprite image we just created.

 
function create_stylesheet() 
{ 
     $this->icon_per_row_count = 0; 
     $this->row_count = 0; 
     $this->x_position = ($this->x_offset * (-1)); 
     $this->y_position = ($this->y_offset * (-1)); 
 
     $create_css = fopen($this->path.'.css', 'a'); 
     $base_class = strtolower($this->target_name); 
 
     $base_css_rule = 
".$base_class { 
     background-image: url({$this->target_name}.{$this->icon_type}); 
}\n"; 
"; 
 
}

You'll notice above that we are using curly brackets.

This is known as the complex curly syntax.

When defining a string with double quotes, you can wrap your variables in curly braces which separates them form other characters in the string.

This allows you to use your variable name next to any character while keeping the var separate.

It's also more readable than regular concatenation and especially useful when dealing with CSS rules where letters, such as 'px' or 'em', will immediatly follow a property value.

For example: background-position: {$foo}px {$bar}px.

Now that we've define our base rule, we can write this to our CSS file file using the fwrite command.

This command takes two parameters, the source file we're writing to and the content we'll be writing.

 
function create_stylesheet() 
{ 
     $this->icon_per_row_count = 0; 
     $this->row_count = 0; 
     $this->x_position = ($this->x_offset * (-1)); 
     $this->y_position = ($this->y_offset * (-1)); 
 
     $create_css = fopen($this->path.'.css', 'a'); 
     $base_class = strtolower($this->target_name); 
 
     $base_css_rule = 
".$base_class { 
     background-image: url({$this->target_name}.{$this->icon_type}); 
}\n"; 
"; 
 
     fwrite($create_css, $base_css_rule); 
 
}

6. Writing specific CSS Class rules within a foreach loop

With our base rule in place, we will now iterate through each individual 'icon_name'.

Above, you'll notice that we haven't closed our CSS file yet.

This is good as we won't need to modify it's permissions with chmod since it's already open.

In continuation, each icon will have a different position along the X axis so we'll need to recalculate the X position before each new rule.

Additionally, once we reach the 'icons_per_row' limit specified in our Sprite Builder FORM, we'll need to recalculate the icons position along the Y axis.

Here is a general outline of the steps we'll take here:

  • Begin a foreach loop for all of the 'icon_names' within our 'icon_name' array and immediatly convert the filename to lower case characters.
    • Define the new CSS rule for the current item in our iteration using the x_position and y_position properties
    • Write the new CSS rule to our CSS file which is still open
    • Increment our 'icon_per_row_count' property by 1
    • Determine if we've reached the 'icons_per_row' limit by comparing the value of our 'icons_per_row' attribute to that of our 'icon_per_row_count' property
      • If the number of icons we iterated through, 'icon_per_row_count', matches the 'icons_per_row' limit, we have reach the end of the images for this row. As such, we'll need to recalculate our x_position and y_positions accordingly
        • We'll adjust the y_position to move down to the next row - we do this by 'moving the image up'
        • We'll 'reset' the x_position back to the start of the icons for this row - the far left side of the sprite
      • Additionally, we will reset our 'icon_per_row_count' to 0 and increment our 'row_count' by 1
    • If we haven't reached the 'icons_per_row' limit, we'll recalculate our 'x_position' property to move the background-position further along the x-axis to the next icon.
  • Terminate the foreach loop
  • Close the CSS file as we have finished writing all of the new class rules

Here's how the code will look, thus far, beginning with the foreach loop:

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $new_css_rule); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position - $this->y_offset - $this->icon_height; 
                    $this->x_position = ($this->x_offset * (-1)); 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position - $this->x_offset - $this->icon_width; 
               } 
          } 
          fclose($create_css);

Within the loop, you'll see that we begin by defining our new CSS rule. We'll use the base 'x_position' and 'y_position' we defined earlier.

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
          }

Next, we'll write this string to the CSS file using the fwrite command

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
          }

Then, we'll increment our 'icon_per_row_count' by 1

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
               $this->icon_per_row_count++; 
          }

Next, we'll check to see if we've reached the end of the images along the x-axis (horizontally).

We do this by comparing the current image count to the 'images_per_row' property which was defined in our 'Sprite Builder' FORM.

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
 
               } 
          }

If the values match, we have reached the end of the icons for this row and we we'll need to do the following:

  • Recalculate the y_position for our rules as we need to move down to the next row on the sprite image.
  • Reset the x_position for the next CSS rule as we are now working from the far left side of the sprite
  • Reset our 'icon_per_row_count' as we have not written any rules for the images on this row yet
  • Increment our 'row_count' by 1 as we have now moved down a row

The calculation we use to determine the icons new position along the y-axis (vertically) will be a mirror image of the calculation we use to determine the x position for each icon.

We simply need to take the current y_position, subtract the y_offset from it and then subtract the icons height from it as well.

This will effectively move the image 'up' bringing the next row into the 'viewable' area.

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position - $this->y_offset - $this->icon_height; 
                    $this->x_position = ($this->x_offset * (-1)); 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
          }

If the values don't match, we have not reached the end of the icons on this row.

We'll need to recalculate the 'x_position' property in order to move the background-position further down along the x-axis to the location of the next icon.

We do so by taking the current 'x_position' and subtracting the 'x_offset' property, which was defined in our Sprite Builder FORM, and then subtracting the icons width, also defined in our Sprite Builder FORM.

This will, basically, scroll our image to the 'left' bringing the next icon into the 'viewable' area.

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position - $this->y_offset - $this->icon_height; 
                    $this->x_position = ($this->x_offset * (-1)); 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position - $this->x_offset - $this->icon_width; 
               } 
          }

7. Finishing up

Now that we've iterated through all of our 'icon_names' and defined a new CSS class name and rule for each one them we can go ahead and close this file.

That's it for our 'create_stylesheet' method!

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $base_css_rule); 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position - $this->y_offset - $this->icon_height; 
                    $this->x_position = ($this->x_offset * (-1)); 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position - $this->x_offset - $this->icon_width; 
               } 
               fclose($create_css); 
          }

7. The full method

Here is the full create_stylesheet() method in its entirety:

 
     function create_stylesheet() 
     { 
          $this->icon_per_row_count = 0; 
          $this->row_count = 0; 
          $this->x_position = ($this->x_offset * (-1)); 
          $this->y_position = ($this->y_offset * (-1)); 
 
          $create_css = fopen($this->path.'.css', 'a'); 
          $base_class = strtolower($this->target_name); 
 
          $base_css_rule = 
".$base_class { 
     background-image: url({$this->target_name}.{$this->icon_type}); 
}\n"; 
          fwrite($create_css, $base_css_rule); 
 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_css_rule = 
".{$icon_name} { 
     background-position: {$this->x_position}px {$this->y_position}px; 
} 
"; 
               fwrite($create_css, $new_css_rule); 
 
               $this->icon_per_row_count++; 
 
               if ($this->icon_per_row_count == $this->icons_per_row) 
               { 
                    $this->y_position = $this->y_position - $this->y_offset - $this->icon_height; 
                    $this->x_position = ($this->x_offset * (-1)); 
                    $this->icon_per_row_count = 0; 
                    $this->row_count++; 
               } 
               else 
               { 
                    $this->x_position = $this->x_position - $this->x_offset - $this->icon_width; 
               } 
          } 
          fclose($create_css); 
     }

Sprite Builder Method Three - Creating the HTML preview


1. Method overview

Our last method will be the create_html function.

This method will output an HTML preview for our image sprite and list the corresponding class names for each image.

We'll start off by defining a few base settings. Then, we'll create the HTML HEAD as well as part of the BODY.

In the HEAD, we'll define a few CSS rules for the page content. Some of these rules will be dynamic, relative to the dimensions of our icons.

Once we write this base data to our HTML file, we'll begin iterating through our 'icon_name' array with a foreach loop.

Within this loop, we'll create a new DIV, SPAN and P ELEMENT for each icon.

Our SPAN ELEMENT will have be given CLASS names corresponding to the 'icon_name' we're working with, as well as the target name for our sprite image, both converted to lowercase.

Once we write all this data to our HTML file we'll append a new string to the file which will close out all open TAGS.

Then, we'll close out the HTML file itself.

2. Base settings

Before we go any further we're going to define a property within this method.

  • div_width - Simply stated, we are defining the width of the container for the icon and text. We'll add 245px to the width of the icon we are working with. In most cases, this will be sufficient to contain both the icon and the text. In retrospect, one could get the length of every 'icon_name' in the array and set the width of this DIV to equal the length of the longest name plus the icons width. But, for simplicities sake, let's just use 245px.
 
     function create_html() 
     { 
          $this->div_width = $this->icon_width + 245; 
     }

3. Creating the HTML page

With that out of the way, we are going to create our new HTML file with the fopen command in 'a' mode.

This will create the file if it doesn't already exist and write all new data to the end of the file.

We will concatenate our 'path' setting from the Sprite Builder FORM with the 'html' file extension.

 
     function create_html() 
     { 
          $this->div_width = $this->icon_width + 245; 
 
          $sprite_html = fopen($this->path.'.html', 'a'); 
     }

4. Getting started with our HTML document

With the new HTML file created and open, we can now create our HEAD element.

Additionally, we'll open up our BODY TAG, a DIV for all of our content as well as a level one HEADER ELEMENT which will server as the page title.

Below, you'll notice that we are echoing out our 'target_name' property as part of the page title, our 'icon_height' property as the height for DIV.icon and our 'div_width' property as the width of DIV.icon.

Additionally, we'll be using our 'icon_height' and 'icon_width' properties as the height and width values for the SPAN which will contain the background image.

Lastly, we'll echo out our 'target_name' again in our level one HEADER element as well.

 
     function create_html() 
     { 
          $this->div_width = $this->icon_width + 245; 
          $sprite_html = fopen($this->path.'.html', 'a'); 
 
          $html_head = 
"<!doctype html> 
<html lang='en'> 
 
<head> 
     <title>{$this->target_name} sprite classes</title> 
     <meta charset='utf-8'> 
 
     <link rel='stylesheet' type='text/css' href='{$this->target_name}.css'> 
 
     <style type='text/css'> 
          H1 
          { 
               color: #434343; 
               font: small-caps bold 33.1pt Helvetica; 
               margin-left: 20px; 
               text-align: left; 
          } 
          DIV#content 
          { 
               margin: 0 auto; 
          } 
          DIV.icon 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               margin: 0px 0px 25px 20px; 
               width: {$this->div_width}px; 
          } 
          DIV.icon SPAN 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               width: {$this->icon_width}px; 
          } 
          DIV.icon P 
          { 
               font: 10pt/{$this->icon_height}px Helvetica; 
               margin: 0 0 0 45px; 
          } 
     </style> 
</head> 
 
<body> 
 
     <div id='content'> 
 
         <h1>{$this->target_name} sprite classes</h1> 
"; 
     }

You'll notice above that we are using curly brackets.

This is known as the complex curly syntax.

When defining a string with double quotes, you can wrap your variables in curly braces which separates them form other characters in the string.

This allows you to use your variable name next to any character while keeping the var separate.

It's also more readable than regular concatenation and especially useful when dealing with CSS rules where letters, such as 'px' or 'em', will immediatly follow a property value.

For example: background-position: {$foo}px {$bar}px.

Now that we've defined our HEAD and opened up our BODY TAG as well as a container DIV, we can write this data to our HTML file file using the fwrite command.

We just need to specify the file we are writing to as well as the content we're writing.

 
     function create_html() 
     { 
          $this->div_width = $this->icon_width + 245; 
          $sprite_html = fopen($this->path.'.html', 'a'); 
 
          $html_head = 
"<!doctype html> 
<html lang='en'> 
 
<head> 
     <title>{$this->target_name} sprite classes</title> 
     <meta charset='utf-8'> 
 
     <link rel='stylesheet' type='text/css' href='{$this->target_name}.css'> 
 
     <style type='text/css'> 
          H1 
          { 
               color: #434343; 
               font: small-caps bold 33.1pt Helvetica; 
               margin-left: 20px; 
               text-align: left; 
          } 
          DIV#content 
          { 
               margin: 0 auto; 
          } 
          DIV.icon 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               margin: 0px 0px 25px 20px; 
               width: {$this->div_width}px; 
          } 
          DIV.icon SPAN 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               width: {$this->icon_width}px; 
          } 
          DIV.icon P 
          { 
               font: 10pt/{$this->icon_height}px Helvetica; 
               margin: 0 0 0 45px; 
          } 
     </style> 
</head> 
 
<body> 
 
     <div id='content'> 
 
         <h1>{$this->target_name} sprite classes</h1> 
"; 
          fwrite($sprite_html, $html_head); 
     }

5. Creating dynamic HTML elements for each icon

We can now begin iterating through our 'icon_name' array with a foreach loop.

Within this loop, we'll first convert the icon name to lowercase.

Then, we'll create a DIV which will contain a SPAN for our icon image as well as a P for the class names associated with this image.

The SPAN's class, as well as the paragraph's text, will both use our 'target_name' and 'icon_name' name properties.

Remember, the 'target_name' was specified in our Sprite Builder FORM.

It will serve as the name of our Sprite Image as well as the default class name for all images in this sprite.

The only CSS property associated with the 'target_name' will be 'background-image' property and it's value will be the sprite image itself.

All of the other class names, which we'll derive from the 'icon_name' array, will have one CSS property - the 'background-position' of the sprite where the image corresponding to this SPAN's class is located.

Here's how the foreach loop will look:

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_paragraph = 
" 
          <div class='icon'> 
               <span class='{$this->target_name} {$icon_name}'></span> 
                
 
.{$this->target_name} .{$icon_name} 
 
 
          </div> 
"; 
 
          }

Once we defined our content in a string, we'll go ahead and write it to our HTML file using the fwrite command.

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_paragraph = 
" 
          <div class='icon'> 
               <span class='{$this->target_name} {$icon_name}'></span> 
                
 
.{$this->target_name} .{$icon_name} 
 
 
          </div> 
"; 
               fwrite($sprite_html, $new_paragraph); 
          }

With all of our fresh content written to the file, we'll terminate the foreach loop and then create a new string which contains the closing TAGS for our HTML file.

We'll write this data to the HTML page and then close the page itself and that's it!

 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_paragraph = 
" 
          <div class='icon'> 
               <span class='{$this->target_name} {$icon_name}'></span> 
                
 
.{$this->target_name} .{$icon_name} 
 
 
          </div> 
"; 
               fwrite($sprite_html, $new_div); 
          } 
 
          $close_html = 
'    </div> 
</body>'; 
 
          fwrite($sprite_html, $close_html); 
          fclose($sprite_html);

6. The full method

Here is the full create_html() method in its entirety:

 
     function create_html() 
     { 
 
          $this->div_width = $this->icon_width + 245; 
 
          $sprite_html = fopen($this->path.'.html', 'a'); 
          $html_head = 
"<!doctype html> 
<html lang='en'> 
 
<head> 
     <title>{$this->target_name} sprite classes</title> 
     <meta charset='utf-8'> 
 
     <link rel='stylesheet' type='text/css' href='{$this->target_name}.css'> 
 
     <style type='text/css'> 
          H1 
          { 
               color: #434343; 
               font: small-caps bold 33.1pt Helvetica; 
               margin-left: 20px; 
               text-align: left; 
          } 
          DIV#content 
          { 
               margin: 0 auto; 
          } 
          DIV.icon 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               margin: 0px 0px 25px 20px; 
               width: {$this->div_width}px; 
          } 
          DIV.icon SPAN 
          { 
               float: left; 
               height: {$this->icon_height}px; 
               width: {$this->icon_width}px; 
          } 
          DIV.icon P 
          { 
               font: 10pt/{$this->icon_height}px Helvetica; 
               margin: 0 0 0 45px; 
          } 
     </style> 
</head> 
 
<body> 
 
     <div id='content'> 
 
         <h1>{$this->target_name} sprite classes</h1> 
"; 
 
          fwrite($sprite_html, $html_head); 
 
          foreach($this->icon_name as $icon_name) 
          { 
		$icon_name = strtolower($icon_name); 
		$new_paragraph = 
" 
          <div class='icon'> 
               <span class='{$this->target_name} {$icon_name}'></span> 
                
 
.{$this->target_name} .{$icon_name} 
 
 
          </div> 
"; 
               fwrite($sprite_html, $new_div); 
          } 
 
          $close_html = 
'    </div> 
</body>'; 
 
          fwrite($sprite_html, $close_html); 
          fclose($sprite_html); 
     }

The End


This ends the PHP Sprite Framework tutorial! I hope you've learned something new from this tut and are able to create and use your own "Sprite Frameworks" with ease!

NOTE: A copy of the Quartz and DF Aqua Gloss icon sets will be included with the source code for demo purposes.


Advertisement