Game console controller

We’ve recently given the dimplex.co.uk site a new face lift and stumbled across an interesting problem during development when it came to implementing the new product carousel on their product pages, more specifically, the handling of the images themselves.

The design brief stipulated that the transparent studio style product images required a light grey background behind it, giving the impression of a product floating nicely in the middle of a light grey surrounding.

We had 2 problems here:

1. A lot of the studio style product images didn’t have sufficient transparent space around themselves and we ended up with unsightly results; images would be touching the edges of its container and weren’t sitting in the middle as intended. We needed to cater for these types of images.

2. We have a mix of studio and lifestyle shots. We couldn't just apply the same image style to both types of image; we would have to come up with something magic/clever to distinguish a studio shot from a lifestyle shot and then apply an image style accordingly.

Given that we are ComputerMinds (we massively care about our clients and we love a challenge) and knowing that the client would have to manually go back, edit and re-upload thousands of images, we decided if would be cool if we could come up with a code solution for them. Below is a brief outline as to how we achieved a code solution to a design/content problem. Enjoy!

Lifestyle and studio shots

Our concept was pretty clear; for images that had at least 1 - and no more than 3 - edges that contained transparent pixels, apply a Drupal image style with a custom effect that would “pad” out the image. The idea was, if an image has 4 transparent edges, the image had sufficient space around it. If it had no transparent edges we knew this was a lifestyle product shot, i.e a radiator in a lounge.

I started looking at the possibilities of detecting transparent pixels with PHP and came across a handy function from the PHP GD image library called imagecolorat(). Using this function and some hexadecimal converter madness (please don't ask me to explain!), we can detect what type of pixel we are looking at given a set of coordinates.

// The result of $transparency will be an integer between 0 and 127 
// 127 is transparent, 0 is opaque/solid.
$rgba = imagecolorat($image_resource, $x, $y);
$transparency = ($rgba >> 24) & 0x7F;

Now we needed to run this function for every pixel along on all four edges. So, first things first, grab the image width and height and subtract 1 from the result. Subtracting 1 ensures you won’t hit a PHP notice about being “out of bounds” - we’re not playing a round of golf here :). Next, we need to sort out our coordinate ranges for us to loop over:

// Top side
X = 0
Y = $image_width

// Bottom side
X = $image_height
Y = $image_width

// Left side
X = $image_height
Y = 0

// Right side
X = $image_width
Y = $image_height

For each permutation of coordinates (x=0, y=750, x=1, y=750, x=2, y=750 etc) , we simply check each pixel result from imagecolorat() and save the result to an array for us to check later on. Once we have detected a transparent and a non-transparent pixel (remembering to check our magic number 127), we then break out because we have all the information we need from this particular edge.

After you’ve completed this process for all four sides, we then do a simple check to see we have a mix of transparent and non transparent pixel edges. If we do, then we pass the image along to our custom image style for processing.

Our custom Drupal image style uses the “define canvas” image processor from the contrib module imagecache actions. We define our own image style effect but use imagecache_actions’ “define canvas” processor to transform our image. This is where we add X amount of pixels to increase the “padding” around the image.

In order to create a custom Drupal image style, we would need to implement hook_image_effect_info() and place any effect code into the "effect callback". See below for an example.

/**
 * Implements hook_image_effect_info().
 */
function MY_MODULE_image_effect_info() {
  $effects = array();
  
  // Remember to replace MY_MODULE with the name of your module (in lower case).
  $effects['MY_MODULE_transparent_padding'] = array(
    'label' => t('Transparent padding'),
    'help' => t('Applies padding if an image has a mix of transparent and solid pixels around the edges of an image.'),
    'effect callback' => 'MY_MODULE_transparent_padding_effect_callback',
    'form callback' => 'MY_MODULE_transparent_padding_form',
    'summary theme' => 'transparent_padding_summary',
  );
  
  return $effects;
}

/**
 * Callback for MY_MODULE_transparent_padding image effect.
 */
function MY_MODULE_transparent_padding_effect_callback(stdClass $image, array $data) {
  if ($image->info['mime_type'] == 'image/png') {
    $image_height = ($image->info['height'] - 1);
    $image_width = ($image->info['width'] - 1);
    $image_resource = $image->resource;

    // Do the coordinate magic and determine transparent and non transparent pixels
    // Build up $data array (this will contain background colour and amount of pixels -
    // to pad out the image.
    
    // Use imagecache_actions custom effect "define canvas" and pass in your $data array.
    $success = image_toolkit_invoke('definecanvas', $image, array($data));
    return $success
}

Below is the result of our custom image style effect settings form as defined above in hook_image_effect_info via "form callback". (The form was taken directly from imagecache_actions' definecanvas effect where I made a couple of edits - so credit goes to them)

Custom image style settings page

And the result is shown below: a before and after. Much better! Furthermore, we’ve saved the client from having to manually edit thousands of images and then manually re-upload them. Win win!

Image before processing

 

Image after processing