Imagecache Example: User Profile Pictures

User profile pictures (or avatars) have been around for about as long as online bulletin board systems themselves. Drupal has included this ability for several versions, but we've found it lacking in both user friendliness and consistency.

If you're using the default Drupal user pictures. Your site's users must upload an image exactly to the dimension specifications. The default is 85x85 pixels, and often that will mean a special trip to the GiMP or Photoshop just to make such an image. Additionally, some users might upload a photo which isn't even that big, like a 16x16 icon. Your designers probably aren't going to like creating a design that needs to support an image from 1x1 pixel up to 85x85 pixels.

We've found that we implementing the following system in the community sites we develop solves these problems. Using imagecache and hook_form_alter(), we can make beautifully consistent and easy user profile pictures.

Getting Started
The first thing you need to do is enable user pictures. Head on over to admin/user/settings (in Drupal 5) and you should have the following options at the bottom of the screen.















settings page

Configure your screen so that it is similar to the following.















settings page after

Now if you go to your user account configuration (such as user/1/edit), you should have a photo section such as this. If you don't see anything, make sure that you changed the admin/user/settings Picture support to 'Enabled'.















picture upload

Now we get down to the fun stuff. You'll need to download the imagecache.module and install it. Imagecache module has some steep requirements, so be sure all these things are also setup:

  • You have GD2 installed with JPEG, GIF, and PNG support
  • Clean URLs are Enabled (admin/settings/clean-urls)
  • Open the .htaccess file in you files directory and make sure it is exactly like the following:
      
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    Options None
    Options +FollowSymLinks
      
    

    If you have mod_rewrite_engine disabled in the files directory (a default in some versions of Drupal 4.7) imagecache will not work.

Enable the imagecache module, then open up the imagecache settings page (admin/settings/imagecache). Create a new imagecache preset called 'thumb'. Then setup two actions so your screen looks like this.















imagecache settings

Make sure you 'Scale to fit' the Outside dimensions. Now the resulting image is at least the entered dimensions, so when you crop you'll always remove the larger side. You can play with the settings as you like to get the right display for your website.

Cool, now we've got an imagecache preset configured. Try it out by uploading a photo for your user on the site (at least 100x100 pixels!), then accessing the URL to the cached image directly. Let's say you're user #1 and you've already uploaded a picture using the default location of /files/pictures/picture-1.jpg. Then try accessing the cached image at: /files/imagecache/thumb/files/pictures/picture-1.jpg.

If you don't see an image exactly 100x100 pixels, then review all the steps above.

Okay, now we can really start some coding! The first thing we want to do is actually make Drupal use our new thumbnails for profile pictures.

Open up your template.php file in your theme's directory. If you don't have a template.php file, just create one and open up a php tag (<?php) at the beginning of the file.

We're going to override the default theme_user_picture function. You can just paste in the code below if you like:

  
/**
 * 
 * Insert into your theme's template.php file:
 * 
 * Theme override for user.module
 * Utilized imagecache module to scale down large uploaded profile pictures
 * @param $size
 *   Image size to scale to. Options: thumb (default) and large
 */
function phptemplate_user_picture($account, $size = 'thumb') {
  if (variable_get('user_pictures', 0)) {
    // Display the user's photo if available
    if ($account->picture && file_exists($account->picture)) {
      $picture = theme('imagecache', $size, $account->picture);
    }
    return '
'.$picture.'
'; } }

You might notice that we're doing something a little tricky here. Checkout the original specification for theme_user_picture(). We've cut out a lot of code for simplicity's sake, but we've also added another parameter to the function: $size. We've set its default to 'thumb', so all modules which use the user picture will default to using that imagecache preset. If you desired, you could now create different imagecache presets and use different size images for various places on your site! The user profile page is a page where Lullabot often uses a larger profile picture, such as 250x250 pixels. Wherever you want a larger image, just pass in the imagecache preset as the second parameter, such as theme('user_picture', $user, 'large');.

Let's checkout the before and after pictures!

Before:















profile before

After (much better!)















profile before

Pretty cool, huh? But wait, what if the user wants to change their profile picture? If you upload a new photo now for yourself, you'll notice that the profile picture displayed doesn't change. This is because imagecache isn't smart enough to know that the image has changed, so it doesn't update the thumbnail. Now we get into custom module development (yay!). If you're scared now, don't give up! We're almost there and we're going to do a lot of cool stuff! If you don't want to do the programming, you can just skip to the bottom and download the zip file (imagecache_profiles.zip) containing this module.

Okay, rather than split up the code I'll paste it all right here. Create a new module directory called 'imagecache_profiles'. Then create a new text file, 'imagecache_profiles.module' in that directory. Paste in the code below:

  

/**
 * Implementation of hook_help().
 */
function imagecache_profiles_help($section) {
  switch($section) {
    case 'admin/modules#description':
      return t('utilizes imagecache presets for user profile pictures');
  }
}

/**
 * Implementation of hook_form_alter().
 */
function imagecache_profiles_form_alter($form_id, &$form) {
  switch($form_id) {
    case 'user_edit':
      $form['#validate']['imagecache_profiles_user_edit_validate'] = array();
      $form['#submit']['imagecache_profiles_user_edit_submit'] = array();
      break;
  }
}

/**
 * Additional form validation for the user_edit form
 */
function imagecache_profiles_user_edit_validate($form_id, $form_values) {
  // Add a minimum size requirement to the image upload form
  if ($info = file_check_upload('picture_upload')) {
    $image_info = image_get_info($form_values['picture']);
    if ($image_info['width'] < 160 || $image_info['height'] < 160) {
      form_set_error('picture_upload',t('Your profile image must be at least 160 pixels wide and tall (your image was @width x @height pixels).',array('@width' => $image_info['width'], '@height' => $image_info['height'])));
    }
  }
}

/**
 * Check for new or deleted uploads and clear the imagecache if necessary
 */
function imagecache_profiles_user_edit_submit($form_id, $form_values) {
  if (file_check_upload('picture_upload') || $form_values['picture_delete']) {
    imagecache_image_flush($form_values['picture']);
  }
}
  

Note that this is made to work with Drupal 4.7 also (hence the hook_help implementation). If you're running Drupal 5, you'll also need to create imagecache_profiles.info file and paste this code:

  
; $Id$
name = Imagecache Profile Pictures
description = Utilizes imagecache presets for user profile pictures.
  

Save and enable your module, now we can upload new photos and they will automatically be updated by imagecache! Let's review our code piece by piece.

hook_form_alter

  

/**
 * Implementation of hook_form_alter().
 */
function imagecache_profiles_form_alter($form_id, &$form) {
  switch($form_id) {
    case 'user_edit':
      $form['#validate']['imagecache_profiles_user_edit_validate'] = array();
      $form['#submit']['imagecache_profiles_user_edit_submit'] = array();
      break;
  }
}
  

This is a very powerful piece of code. hook_form_alter() allows you to edit the behavior of any form in all Drupal. What we're doing here is adding two additional properties to the form, additional validation and additional submit handling. The name of the function is the second key in the array (such as 'imagecache_profiles_user_edit_validate') and we're passing in an empty array, meaning we don't need to send any additional parameters.

imagecache_profiles_user_edit_validate

  
/**
 * Additional form validation for the user_edit form
 */
function imagecache_profiles_user_edit_validate($form_id, $form_values) {
  // Add a minimum size requirement to the image upload form
  if ($info = file_check_upload('picture_upload')) {
    $image_info = image_get_info($form_values['picture']);
    if ($image_info['width'] < 160 || $image_info['height'] < 160) {
      form_set_error('picture_upload',t('Your profile image must be at least 160 pixels wide and tall (your image was @width x @height pixels).',array('@width' => $image_info['width'], '@height' => $image_info['height'])));
    }
  }
}
  

This is the first function we added to the user_edit form. Remember way back when we set the user profile picture settings? We required that all user photos are at least 160 pixels before upload. This small function ensures that minimum size is actually enforced.

imagecache_profiles_user_edit_submit

  
/**
 * Check for new or deleted uploads and clear the imagecache if necessary
 */
function imagecache_profiles_user_edit_submit($form_id, $form_values) {
  if (file_check_upload('picture_upload') || $form_values['picture_delete']) {
    imagecache_image_flush($form_values['picture']);
  }
}
  

Finally, this last piece of code performs the necessary magic to make sure our cached images are always up-to-date. Imagecache.module provides a mechanism for clearing the cache of any particular file it has saved in all presets. Just pass in the file path the original, and it deletes all the cached versions. They'll automatically be recreated next time the image is requested.

Phew, we covered a lot of code. I hope everyone enjoyed and happy imagecaching!

Download the Code (imagecache_profiles.zip)

Get in touch with us

Tell us about your project or drop us a line. We'd love to hear from you!