? .cache
? .project
? .projectOptions
? files
? test.patch
? misc/Thumbs.db
? misc/farbtastic/Thumbs.db
? modules/gd
? modules/imagemagick
? sites/all/modules
? sites/default/settings.php
Index: includes/image.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/image.inc,v
retrieving revision 1.21
diff -u -r1.21 image.inc
--- includes/image.inc	12 May 2007 05:51:20 -0000	1.21
+++ includes/image.inc	8 Jun 2007 18:32:54 -0000
@@ -4,76 +4,69 @@
 /**
  * Return a list of available toolkits.
  *
- * @return An array of toolkit name => descriptive title.
+ * @return 
+ *   An array with the names of all enabled, image toolkit modules.
  */
 function image_get_available_toolkits() {
-  $toolkits = file_scan_directory('includes', 'image\..*\.inc$');
+  static $toolkits;
 
-  $output = array();
-  foreach ($toolkits as $file => $toolkit) {
-    include_once "./$file";
-    $function = str_replace('.', '_', $toolkit->name) .'_info';
-    if (function_exists($function)) {
-      $info = $function();
-      $output[$info['name']] = $info['title'];
-    }
+  if (!isset($toolkits)) {
+    $toolkits = module_implements('image_toolkit', TRUE);
   }
-  $output['gd'] = t('Built-in GD2 toolkit');
-  return $output;
+  
+  return $toolkits;
 }
 
 /**
  * Retrieve the name of the currently used toolkit.
  *
- * @return String containing the name of the toolkit.
+ * @return 
+ *   String containing the name of the toolkit, or FALSE if none is available.
  */
 function image_get_toolkit() {
-  static $toolkit;
-  if (!$toolkit) {
-    $toolkit = variable_get('image_toolkit', 'gd');
-    $toolkit_file = './includes/image.'. $toolkit .'.inc';
-    if ($toolkit != 'gd' && file_exists($toolkit_file)) {
-      include_once $toolkit_file;
-    }
-    elseif (!image_gd_check_settings()) {
-      $toolkit = FALSE;
-    }
+  $toolkit = variable_get('image_toolkit', 'gd');
+
+  // Verify that the image toolkit is available.
+  if (isset($toolkit) && module_exists($toolkit)) {
+    return $toolkit;
   }
 
-  return $toolkit;
+  return FALSE;
 }
 
 /**
  * Invokes the given method using the currently selected toolkit.
  *
- * @param $method A string containing the method to invoke.
- * @param $params An optional array of parameters to pass to the toolkit method.
- *
- * @return Mixed values (typically Boolean for successful operation).
+ * @param $method
+ *   A string containing the method to invoke.
+ * @param $source
+ *   The file path to the source image.
+ * @param $destination
+ *   The file path to the destination image.
+ * @param $params
+ *   An optional array of parameters to pass to the toolkit method.
+ *   Possible keys and values are:
+ *     x             The top left co-ordinate of the crop area (x axis value),
+ *     y             The top left co-ordinate of the crop area (y axis value).
+ *     width         The target width for resize.
+ *     height        The target height for resize.
+ *     degrees       The number of (clockwise) degrees to rotate the image.
+ *     bg_color      An hexidecimal integer specifying a color. E.g. 0x000000 
+ *                   for black, 0xff00ff for magenta, and 0xffffff for white.
+ * @return
+ *   Mixed values (typically Boolean for successful operation).
  */
-function image_toolkit_invoke($method, $params = array()) {
+function image_toolkit_invoke($method, $source, $destination, $params = array()) {
   if ($toolkit = image_get_toolkit()) {
-    $function = 'image_'. $toolkit .'_'. $method;
-    if (function_exists($function)) {
-      return call_user_func_array($function, $params);
-    }
-    else {
-      watchdog('php', 'The selected image handling toolkit %toolkit can not correctly process %function.', array('%toolkit' => $toolkit, '%function' => $function), WATCHDOG_ERROR);
-      return FALSE;
-    }
-  }
-  else {
-    if ($method == 'settings') {
-      return image_gd_settings();
-    }
+    return module_invoke($toolkit, 'image_toolkit', $method, $source, $destination, $params);
   }
 }
 
-
 /**
  * Get details about an image.
  *
- * @return array containing information about the image
+ * @return 
+ *   An array containing the following information about the image:
  *      'width': image's width in pixels
  *      'height': image's height in pixels
  *      'extension': commonly used extension for the image
@@ -110,12 +103,16 @@
  *
  * The resulting image always has the exact target dimensions.
  *
- * @param $source         The file path of the source image
- * @param $destination    The file path of the destination image
- * @param $width          The target width
- * @param $height         The target height
- *
- * @return TRUE or FALSE, based on success
+ * @param $source
+ *   The file path of the source image.
+ * @param $destination
+ *   The file path of the destination image.
+ * @param $width
+ *   The target width in pixels.
+ * @param $height
+ *   The target height in pixels.
+ * @return
+ *   TRUE or FALSE, based on success.
  */
 function image_scale_and_crop($source, $destination, $width, $height) {
   $info = image_get_info($source);
@@ -124,8 +121,10 @@
   $x = round(($info['width'] * $scale - $width) / 2);
   $y = round(($info['height'] * $scale - $height) / 2);
 
-  if (image_toolkit_invoke('resize', array($source, $destination, $info['width'] * $scale, $info['height'] * $scale))) {
-    return image_toolkit_invoke('crop', array($destination, $destination, $x, $y, $width, $height));
+  $params = array('width' => $info['width'] * $scale, 'height' => $info['height'] * $scale);
+  if (image_toolkit_invoke('resize', $source, $destination, $params)) {
+    $params = array('x' => $x, 'y' => $y, 'width' => $width, 'height' => $height);
+    return image_toolkit_invoke('crop', $destination, $destination, $params);
   }
   return FALSE;
 }
@@ -136,12 +135,16 @@
  *
  * The resulting image can be smaller for one or both target dimensions.
  *
- * @param $source         The file path of the source image
- * @param $destination    The file path of the destination image
- * @param $width          The target width
- * @param $height         The target height
- *
- * @return True or FALSE, based on success
+ * @param $source
+ *   The file path of the source image.
+ * @param $destination
+ *   The file path of the destination image.
+ * @param $width
+ *   The target width in pixels.
+ * @param $height
+ *   The target height in pixels.
+ * @return
+ *   TRUE or FALSE, based on success.
  */
 function image_scale($source, $destination, $width, $height) {
   $info = image_get_info($source);
@@ -153,206 +156,76 @@
 
   $aspect = $info['height'] / $info['width'];
   if ($aspect < $height / $width) {
-    $width = (int)min($width, $info['width']);
-    $height = (int)round($width * $aspect);
+    $params['width'] = (int) min($width, $info['width']);
+    $params['height'] = (int) round($width * $aspect);
   }
   else {
-    $height = (int)min($height, $info['height']);
-    $width = (int)round($height / $aspect);
+    $params['height'] = (int) min($height, $info['height']);
+    $params['width'] = (int) round($height / $aspect);
   }
 
-  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
+  return image_toolkit_invoke('resize', $source, $destination, $params);
 }
 
 /**
  * Resize an image to the given dimensions (ignoring aspect ratio).
  *
- * @param $source        The filepath of the source image.
- * @param $destination   The file path of the destination image.
- * @param $width         The target width.
- * @param $height        The target height.
+ * @param $source
+ *   The filepath of the source image.
+ * @param $destination
+ *   The file path of the destination image.
+ * @param $width
+ *   The target width in pixels.
+ * @param $height
+ *   The target height in pixels.
+ * @return
+ *   TRUE or FALSE, based on success.
  */
 function image_resize($source, $destination, $width, $height) {
-  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
+  $params = array('width' => $width, 'height' => $height);
+  return image_toolkit_invoke('resize', $source, $destination, $params);
 }
 
 /**
  * Rotate an image by the given number of degrees.
  *
- * @param $source  The filepath of the source image
- * @param $destination    The file path of the destination image
- * @param $degrees The number of (clockwise) degrees to rotate the image
- */
-function image_rotate($source, $destination, $degrees) {
-  return image_toolkit_invoke('rotate', array($source, $destination, $degrees));
+ * @param $source
+ *   The filepath of the source image.
+ * @param $destination
+ *   The file path of the destination image.
+ * @param $degrees
+ *   The number of (clockwise) degrees to rotate the image.
+ * @param $bg_color
+ *   An hexidecimal integer specifying the background color to use for the 
+ *   uncovered area of the image after the rotation. E.g. 0x000000 for black, 
+ *   0xff00ff for magenta, and 0xffffff for white.
+ * @return
+ *   TRUE or FALSE, based on success.
+ */
+function image_rotate($source, $destination, $degrees, $bg_color = 0x000000) {
+  $params = array('degrees' => $degrees, 'bg_color' => $bg_color);
+  return image_toolkit_invoke('rotate', $source, $destination, $params);
 }
 
 /**
  * Crop an image to the rectangle specified by the given rectangle.
  *
- * @param $source        The filepath of the source image
- * @param $destination   The file path of the destination image
- * @param $x             The top left co-ordinate of the crop area (x axis value)
- * @param $y             The top left co-ordinate of the crop area (y axis value)
- * @param $width         The target width
- * @param $height        The target height
+ * @param $source
+ *   The filepath of the source image.
+ * @param $destination
+ *   The file path of the destination image.
+ * @param $x
+ *   The top left co-ordinate of the crop area (x axis value).
+ * @param $y
+ *   The top left co-ordinate of the crop area (y axis value).
+ * @param $width
+ *   The target width in pixels.
+ * @param $height
+ *   The target height in pixels.
+ * @return 
+ *   TRUE or FALSE, based on success.
  */
 function image_crop($source, $destination, $x, $y, $width, $height) {
-  return image_toolkit_invoke('crop', array($source, $destination, $x, $y, $width, $height));
-}
-
-/**
- * GD2 toolkit functions
- * With the minimal requirements of PHP 4.3 for Drupal, we use the built-in version of GD.
- */
-
-/**
- * Retrieve settings for the GD2 toolkit.
- */
-function image_gd_settings() {
-  if (image_gd_check_settings()) {
-    $form = array();
-    $form['status'] = array('#value' => t('The built-in GD2 toolkit is installed and working properly.'));
-
-    $form['image_jpeg_quality'] = array(
-      '#type' => 'textfield',
-      '#title' => t('JPEG quality'),
-      '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
-      '#size' => 10,
-      '#maxlength' => 3,
-      '#default_value' => variable_get('image_jpeg_quality', 75),
-      '#field_suffix' => t('%'),
-    );
-
-    return $form;
-  }
-  else {
-    form_set_error('image_toolkit', t('The built-in GD image toolkit requires that the GD module for PHP be installed and configured properly. For more information see <a href="@url">PHP\'s image documentation</a>.', array('@url' => 'http://php.net/image')));
-    return FALSE;
-  }
-}
-
-/**
- * Verify GD2 settings (that the right version is actually installed).
- *
- * @return boolean
- */
-function image_gd_check_settings() {
-  if ($check = get_extension_funcs('gd')) {
-    if (in_array('imagegd2', $check)) {
-      // GD2 support is available.
-      return TRUE;
-    }
-  }
-  return FALSE;
-}
-
-/**
- * Scale an image to the specified size using GD.
- */
-function image_gd_resize($source, $destination, $width, $height) {
-  if (!file_exists($source)) {
-    return FALSE;
-  }
-
-  $info = image_get_info($source);
-  if (!$info) {
-    return FALSE;
-  }
-
-  $im = image_gd_open($source, $info['extension']);
-  if (!$im) {
-    return FALSE;
-  }
-
-  $res = imageCreateTrueColor($width, $height);
-  if ($info['extension'] == 'png') {
-    $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
-    imagealphablending($res, FALSE);
-    imagefilledrectangle($res, 0, 0, $width, $height, $transparency);
-    imagealphablending($res, TRUE);
-    imagesavealpha($res, TRUE);
-  }
-  imageCopyResampled($res, $im, 0, 0, 0, 0, $width, $height, $info['width'], $info['height']);
-  $result = image_gd_close($res, $destination, $info['extension']);
-
-  imageDestroy($res);
-  imageDestroy($im);
-
-  return $result;
-}
-
-/**
- * Rotate an image the given number of degrees.
- */
-function image_gd_rotate($source, $destination, $degrees, $bg_color = 0) {
-  if (!function_exists('imageRotate')) {
-    return FALSE;
-  }
-
-  $info = image_get_info($source);
-  if (!$info) {
-    return FALSE;
-  }
-
-  $im = image_gd_open($source, $info['extension']);
-  if (!$im) {
-    return FALSE;
-  }
-
-  $res = imageRotate($im, $degrees, $bg_color);
-  $result = image_gd_close($res, $destination, $info['extension']);
-
-  return $result;
-}
-
-/**
- * Crop an image using the GD toolkit.
- */
-function image_gd_crop($source, $destination, $x, $y, $width, $height) {
-  $info = image_get_info($source);
-  if (!$info) {
-    return FALSE;
-  }
-
-  $im = image_gd_open($source, $info['extension']);
-  $res = imageCreateTrueColor($width, $height);
-  imageCopy($res, $im, 0, 0, $x, $y, $width, $height);
-  $result = image_gd_close($res, $destination, $info['extension']);
-
-  imageDestroy($res);
-  imageDestroy($im);
-
-  return $result;
-}
-
-/**
- * GD helper function to create an image resource from a file.
- */
-function image_gd_open($file, $extension) {
-  $extension = str_replace('jpg', 'jpeg', $extension);
-  $open_func = 'imageCreateFrom'. $extension;
-  if (!function_exists($open_func)) {
-    return FALSE;
-  }
-  return $open_func($file);
-}
-
-/**
- * GD helper to write an image resource to a destination file.
- */
-function image_gd_close($res, $destination, $extension) {
-  $extension = str_replace('jpg', 'jpeg', $extension);
-  $close_func = 'image'. $extension;
-  if (!function_exists($close_func)) {
-    return FALSE;
-  }
-  if ($extension == 'jpeg') {
-    return $close_func($res, $destination, variable_get('image_jpeg_quality', 75));
-  }
-  else {
-    return $close_func($res, $destination);
-  }
-}
-
-
+  $params = array('x' => $x, 'y' => $y, 'width' => $width, 'height' => $height);
+  return image_toolkit_invoke('crop', $source, $destination, $params);
+}
\ No newline at end of file
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.491
diff -u -r1.491 system.module
--- modules/system/system.module	8 Jun 2007 12:51:59 -0000	1.491
+++ modules/system/system.module	8 Jun 2007 19:16:03 -0000
@@ -275,10 +275,32 @@
   );
   $items['admin/settings/image-toolkit'] = array(
     'title' => 'Image toolkit',
-    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
+    'description' => 'Choose which image toolkit to use for resizing or rotating images.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_image_toolkit_settings'),
   );
+  $toolkits = image_get_available_toolkits();
+  if ($toolkits) {
+    $items['admin/settings/image-toolkit/list'] = array(
+      'title' => 'List',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => -1,
+    );
+    $items['admin/settings/image-toolkit/config'] = array(
+      'title' => 'Configure',
+      'type' => MENU_LOCAL_TASK,
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array(image_get_toolkit() .'_settings_form'),
+    );
+    foreach ($toolkits as $toolkit) {
+      $items['admin/settings/image-toolkit/config/'. $toolkit] = array(
+        'title' => $toolkit,
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array($toolkit .'_settings_form'),
+        'type' => $toolkit == image_get_toolkit() ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
+      );
+    }
+  }
   $items['admin/content/rss-publishing'] = array(
     'title' => 'RSS publishing',
     'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
@@ -781,20 +803,38 @@
 }
 
 function system_image_toolkit_settings() {
-  $toolkits_available = image_get_available_toolkits();
-  if (count($toolkits_available) > 1) {
-    $form['image_toolkit'] = array(
-      '#type' => 'radios',
-      '#title' => t('Select an image processing toolkit'),
-      '#default_value' => variable_get('image_toolkit', image_get_toolkit()),
-      '#options' => $toolkits_available
-    );
+  // @TODO: This is an in-elegant way to get the module's description from the 
+  // .info file. There should be a function to do this.
+  $modules = module_rebuild_cache();
+  $toolkits_available = array();
+  foreach (image_get_available_toolkits() as $module) {
+    $toolkits_available[$module] = $modules[$module]->info['description'];
   }
-  else {
-    $form['image_toolkit'] = array('#value' => '<p>'. t("No image toolkits found. Drupal will use PHP's built-in GD library for image handling.") .'</p>');
+
+  switch (count($toolkits_available)) {
+    case 0:
+      $form['image_toolkits']['#value'] = t('There are no image toolkit modules enabled. Toolkit modules can be enabled from the <a href="!admin-build-modules">module configuration page</a>.', array('!admin-build-modules' => url('admin/build/modules')));
+      return $form;
+    
+    case 1:
+      // The variable needs to be manually set. Otherwise, if a user has two 
+      // toolkits and disables the selected one they won't be able to select the 
+      // remaing toolkit.
+      $toolkit = key($toolkits_available);
+      variable_set('image_toolkit', $toolkit);
+      $form['image_toolkit']['#value'] = t('The %toolkit module is the only enabled image toolkit. Drupal will use it for resizing, cropping and other image manipulations.', array('%toolkit' => $modules[$toolkit]->info['name']));
+      return $form;
+            
+    default:
+      $form['image_toolkit'] = array(
+        '#type' => 'radios',
+        '#title' => t('Select an image processing toolkit'),
+        '#default_value' => image_get_toolkit(),
+        '#options' => $toolkits_available,
+        '#description' => t('This setting lets you choose which toolkit Drupal uses resizing, cropping and other image manipulations'),
+      );
+      return system_settings_form($form);
   }
-  $form['image_toolkit_settings'] = image_toolkit_invoke('settings');
-  return system_settings_form($form);
 }
 
 function system_rss_feeds_settings() {
--- modules/gd/gd.info
+++ modules/gd/gd.info
@@ -0,0 +1,6 @@
+; $Id: $
+name = GD2
+description = Uses PHP's built-in GD2 image processing support.
+package = Core - optional
+version = VERSION
+core = 6.x

--- modules/gd/gd.install
+++ modules/gd/gd.install
@@ -0,0 +1,35 @@
+<?php
+// $Id: $
+
+function gd_requirements($phase) {
+  $requirements = array();
+
+  if ($phase == 'runtime') {
+    // Check GD library
+    if (function_exists('imagegd2')) {
+      $info = gd_info();
+      $requirements['gd'] = array(
+        'value' => $info['GD Version'],
+      );
+
+      // Check PNG support
+      if (function_exists('imagecreatefrompng')) {
+        $requirements['gd']['severity'] = REQUIREMENT_OK;
+      }
+      else {
+        $requirements['gd']['severity'] = REQUIREMENT_ERROR;
+        $requirements['gd']['description'] = t('The GD library for PHP is enabled, but was compiled without PNG support. Please check the <a href="@url">PHP image documentation</a> for information on how to correct this.', array('@url' => 'http://www.php.net/manual/en/ref.image.php'));
+      }
+    }
+    else {
+      $requirements['gd'] = array(
+        'value' => t('Not installed'),
+        'severity' => REQUIREMENT_ERROR,
+        'description' => t('The GD library for PHP is missing or outdated. Please check the <a href="@url">PHP image documentation</a> for information on how to correct this.', array('@url' => 'http://www.php.net/manual/en/ref.image.php')),
+      );
+    }
+    $requirements['gd']['title'] = t('GD library');
+  }
+
+  return $requirements;
+}

--- modules/gd/gd.module
+++ modules/gd/gd.module
@@ -0,0 +1,100 @@
+<?php
+// $id: $
+
+/**
+ * @file
+ * GD2 toolkit functions
+ */
+
+/**
+ * Settings form for the toolkit.
+ */
+function gd_settings_form() {
+  $form['image_jpeg_quality'] = array(
+    '#type' => 'textfield',
+    '#title' => t('JPEG quality'),
+    '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality, but bigger files.'),
+    '#size' => 10,
+    '#maxlength' => 3,
+    '#default_value' => variable_get('image_jpeg_quality', 75),
+    '#field_suffix' => '%',
+  );
+  return system_settings_form($form);
+}
+
+/**
+ * Implementation of hook_image_toolkit().
+ */
+function gd_image_toolkit($op, $source = NULL, $destination = NULL, $params = array()) {
+  if (!file_exists($source)) {
+    return FALSE;
+  }
+  
+  $info = image_get_info($source);
+  if (!$info) {
+    return FALSE;
+ }
+  
+  $im = _gd_open($source, $info['extension']);
+  if (!$im) {
+    return FALSE;
+  }
+  
+  switch ($op) {
+    case 'crop':
+      $res = imageCreateTrueColor($params['width'], $params['height']);
+      imageCopy($res, $im, 0, 0, $params['x'], $params['y'], $params['width'], $params['height']);
+      break;
+      
+    case 'resize':
+      $res = imageCreateTrueColor($params['width'], $params['height']);
+      if ($info['extension'] == 'png') {
+        $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
+        imagealphablending($res, FALSE);
+        imagefilledrectangle($res, 0, 0, $params['width'], $params['height'], $transparency);
+        imagealphablending($res, TRUE);
+        imagesavealpha($res, TRUE);
+      }
+      imageCopyResampled($res, $im, 0, 0, 0, 0, $params['width'], $params['height'], $info['width'], $info['height']);
+      break;
+      
+    case 'rotate':
+      $res = imageRotate($im, $params['degrees'], $params['bg_color']);
+      break;
+  }
+  $result = _gd_close($res, $destination, $info['extension']);
+
+  imageDestroy($im);
+  imageDestroy($res);
+
+  return $result;
+}
+
+/**
+ * GD helper function to create an image resource from a file.
+ */
+function _gd_open($file, $extension) {
+  $extension = str_replace('jpg', 'jpeg', $extension);
+  $open_func = 'imageCreateFrom'. $extension;
+  if (!function_exists($open_func)) {
+    return FALSE;
+  }
+  return $open_func($file);
+}
+
+/**
+ * GD helper to write an image resource to a destination file.
+ */
+function _gd_close($res, $destination, $extension) {
+  $extension = str_replace('jpg', 'jpeg', $extension);
+  $close_func = 'image'. $extension;
+  if (!function_exists($close_func)) {
+    return FALSE;
+  }
+  if ($extension == 'jpeg') {
+    return $close_func($res, $destination, variable_get('image_jpeg_quality', 75));
+  }
+  else {
+    return $close_func($res, $destination);
+  }
+}

--- modules/imagemagick/imagemagick.info
+++ modules/imagemagick/imagemagick.info
@@ -0,0 +1,6 @@
+; $Id: $
+name = ImageMagick
+description = ImageMagick image toolkit.
+package = Core - optional
+version = VERSION
+core = 6.x

--- modules/imagemagick/imagemagick.module
+++ modules/imagemagick/imagemagick.module
@@ -0,0 +1,146 @@
+<?php
+// $Id: $
+
+/**
+ * @file
+ * ImageMagick toolkit functions
+ */
+
+/**
+ * Settings form for the toolkit.
+ */
+function imagemagick_settings_form() {
+  $form['#after_build'][] = '_imagemagick_version';
+  $form['#validate'][] = '_imagemagick_validate';
+  $form['image_imagemagick_convert'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path to the "convert" binary'),
+    '#default_value' => variable_get('image_imagemagick_convert', '/usr/bin/convert'),
+    '#required' => TRUE,
+  );
+  return system_settings_form($form);
+}
+
+function _imagemagick_version(&$form, &$form_state) {
+  $path = realpath($form_state['values']['image_imagemagick_convert']);
+  if (_imagemagick_check_path($path)) {
+    _imagemagick_convert_exec($path, '-version', $output, $errors);
+    $form['image_imagemagick_version'] = array(
+      '#type' => 'item',
+      '#value' => '<pre>'. check_plain($output) .'</pre>',
+    );
+    $form['buttons']['#weight'] = 10;
+  }
+  else {
+    _imagemagick_validate($form, $form_state);
+  }
+  return $form;
+}
+
+function _imagemagick_validate(&$form, &$form_state) {
+  $path = realpath($form_state['values']['image_imagemagick_convert']);
+  if (!_imagemagick_check_path($path)) {
+    if (ini_get('open_basedir')) {
+      form_set_error('image_imagemagick_convert', t("No file named %file could be found. PHP's <a href='@open-basedir'>open_basedir</a> security resriction may be interfearing with the attempts to locate it.", array('%file' => $path, '@open-basedir' => url('http://us2.php.net/features.safe-mode') )));
+    }
+    else {
+      form_set_error('image_imagemagick_convert', t('The specified ImageMagic path %file does not exist.', array('%file' => $path)));
+    }
+  }
+  return $form;
+}
+
+/**
+ * Simple check if the path given is a file. 
+ */
+function _imagemagick_check_path($path) {
+  return is_file($path);
+}
+
+/**
+ * Implementation of hook_image_toolkit().
+ */
+function imagemagick_image_toolkit($op, $source = NULL, $destination = NULL, $params = array()) {
+  $convert_path = variable_get('image_imagemagick_convert', '/usr/bin/convert');
+  if (!is_file($convert_path)) {
+    drupal_set_message(t("ImageMagick could not be found. The admin will need to set the path on the <a href='!settings'>image toolkit settings</a> page.", array('!settings' => url('admin/settings/imagemagick'))), 'error');
+    return FALSE;
+  }
+
+  switch ($op) {
+    case 'crop':
+      $filter = ' -crop '. intval($params['width']) .'x'. intval($params['height']) .'+'. intval($params['x']) .'+'. intval($params['y']);
+      break;
+      
+    case 'resize':
+      $filter = ' -scale '. intval($params['width']) .'x'. intval($params['height']) .'! -filter QUADRATIC';
+      break;
+      
+    case 'rotate':
+      $filter = ' -rotate '. intval($params['degrees']) .' -background #'. str_pad(dechex($params['bg_color']), 6, 0);
+      break;
+    
+    default:
+      return FALSE;
+  }
+
+  $args = $filter .' '. escapeshellarg($source) .' '. escapeshellarg($destination);
+  if (0 != _imagemagick_convert_exec($convert_path, $args, $output, $errors)) {
+    return FALSE;
+  }
+  return file_exists($destination);
+}
+
+/**
+ * Execute ImageMagick
+ * 
+ * @param $convert_path 
+ *   Full path to the convert binary.
+ * @param $command_args
+ *   String with parameters to pass to convert. This should be properly escaped 
+ *   with escapeshellarg().
+ * @param $output
+ *   Output string.
+ * @param $errors
+ *   Error string.
+ * @return
+ *   Exit code from the convert binary or FALSE on error. 
+ */
+function _imagemagick_convert_exec($convert_path, $command_args, &$output, &$errors) { 
+  if (strstr($_SERVER['SERVER_SOFTWARE'], 'Win32') || strstr($_SERVER['SERVER_SOFTWARE'], 'IIS')) {
+    // use window's start command to avoid the "black window" from showing up:
+    // http://us3.php.net/manual/en/function.exec.php#56599
+    // use /D to run the command from PHP's current working directory so the
+    // file paths don't have to be absolute.
+    $convert_path = 'start "window title" /D'. getcwd() .' /b '. escapeshellarg($convert_path);
+  }
+
+  $descriptors = array(
+    0 => array('pipe', 'r'), // stdin
+    1 => array('pipe', 'w'), // stdout
+    2 => array('pipe', 'w')  // stderr
+  );
+  if ($h = proc_open($convert_path .' '. $command_args, $descriptors, $pipes)) {
+    $output = '';
+    while (!feof($pipes[1])) {
+      $output .= fgets($pipes[1]);
+    }
+
+    $errors = '';
+    while (!feof($pipes[2])) {
+      $errors .= fgets($pipes[2]);
+    }
+
+    #drupal_set_message(t("ImageMagick command: %command", array('%command' => $convert_path .' '. $command_args)));
+    #drupal_set_message(t("ImageMagick output: %output", array('%output' => $output)));
+    if (!empty($errors)) {
+      drupal_set_message(t("ImageMagick reported an error: %error", array('%error' => $errors)), 'error');
+    }
+
+    fclose($pipes[0]);
+    fclose($pipes[1]);
+    fclose($pipes[2]);
+    return proc_close($h);
+  }
+  return FALSE;
+}

