? imageapi.module.20090710
? imageapi_416254-19.patch
? imageapi_416254-24.patch
? imageapi_gd.module.20090710
? imageapi_imagemagick.module.20090710
Index: imageapi.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imageapi/imageapi.module,v
retrieving revision 1.23.2.3
diff -u -p -r1.23.2.3 imageapi.module
--- imageapi.module	18 Mar 2009 08:35:59 -0000	1.23.2.3
+++ imageapi.module	22 Sep 2009 22:54:51 -0000
@@ -362,7 +362,7 @@ function imageapi_image_desaturate(&$ima
  *   An image object or FALSE if there was a problem loading the file. The
  *   image object has the following properties:
  *    - 'source' - The original file path.
- *    - 'info' - The array of information returned by image_get_info()
+ *    - 'info' - The array of information returned by imageapi_get_info()
  *    - 'toolkit' - The name of the image toolkit requested when the image was
  *      loaded.
  *   Image tookits may add additional properties. The caller is advised not to
@@ -375,7 +375,7 @@ function imageapi_image_open($file, $too
   if ($toolkit) {
     $image = new stdClass();
     $image->source = $file;
-    $image->info = image_get_info($file);
+    $image->info = imageapi_get_info($file, $toolkit);
     $image->toolkit = $toolkit;
     if (imageapi_toolkit_invoke('open', $image)) {
       return $image;
@@ -403,7 +403,7 @@ function imageapi_image_close($image, $d
   if ($return = imageapi_toolkit_invoke('close', $image, array($destination))) {
     // Clear the cached file size and refresh the image information.
     clearstatcache();
-    $image->info = image_get_info($destination);
+    $image->info = imageapi_get_info($destination, $image->toolkit);
 
     if (@chmod($destination, 0664)) {
       return $return;
@@ -461,3 +461,42 @@ function imageapi_hex2rgba($hex) {
   return array($r, $g, $b, $a);
 }
 
+/**
+ * Get details about an image.
+ *
+ * Drupal supports GIF, JPG and PNG file formats, and may support 
+ * others depending on which toolkits are installed.
+ * 
+ * @param $filepath
+ *   String specifying the path of the image file.
+ * @param $toolkit
+ *   An optional, image toolkit name to override the default.
+ * @return
+ *   FALSE, if the file could not be found or is not an image. Otherwise, a
+ *   keyed array containing information about the image:
+ *    'width'     - Width in pixels.
+ *    'height'    - Height in pixels.
+ *    'extension' - Commonly used file extension for the image.
+ *    'mime_type' - MIME type, e.g. 'image/jpeg', 'image/gif', 'image/png'.
+ *    'file_size' - File size in bytes.
+ */
+function imageapi_get_info($filepath, $toolkit = FALSE) {
+  if (!is_file($filepath)) {
+    return FALSE;
+  }
+
+  $details = FALSE;
+
+  if (!$toolkit) {
+    $toolkit = imageapi_default_toolkit();
+  }
+  if ($toolkit) {
+    $image = new stdClass();
+    $image->source = $filepath;
+    $image->toolkit = $toolkit;
+    $details = imageapi_toolkit_invoke('get_info', $image);
+  }
+
+  return $details;
+}
+
Index: imageapi_gd.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imageapi/imageapi_gd.module,v
retrieving revision 1.13.2.7
diff -u -p -r1.13.2.7 imageapi_gd.module
--- imageapi_gd.module	17 Apr 2009 00:15:21 -0000	1.13.2.7
+++ imageapi_gd.module	22 Sep 2009 22:54:51 -0000
@@ -397,3 +397,23 @@ function imageapi_gd_unsharp_mask($img, 
 
   return $img;
 }
+
+/**
+ * Get details about an image.
+ *
+ * GD supports only GIF, JPG and PNG file formats.
+ *
+ * @param $image
+ *   An image object.
+ * @return
+ *   FALSE, if the file could not be found or is not an image. Otherwise, a
+ *   keyed array containing information about the image:
+ *    'width'     - Width in pixels.
+ *    'height'    - Height in pixels.
+ *    'extension' - Commonly used file extension for the image.
+ *    'mime_type' - MIME type ('image/jpeg', 'image/gif', 'image/png').
+ *    'file_size' - File size in bytes.
+ */
+function imageapi_gd_image_get_info($image) {
+  return image_get_info($image->source);
+}
Index: imageapi_imagemagick.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imageapi/imageapi_imagemagick.module,v
retrieving revision 1.17.2.5
diff -u -p -r1.17.2.5 imageapi_imagemagick.module
--- imageapi_imagemagick.module	29 May 2009 17:48:32 -0000	1.17.2.5
+++ imageapi_imagemagick.module	22 Sep 2009 22:54:51 -0000
@@ -31,9 +31,9 @@ function imageapi_imagemagick_settings_f
 
   $form['imageapi_imagemagick_binary'] = array(
     '#type' => 'fieldset',
-    '#title' => t('ImageMagick Binary'),
+    '#title' => t('ImageMagick Binaries'),
     '#collapsible' => FALSE,
-    '#description' => t('ImageMagick is a standalone program used to manipulate images. To use it, it must be installed on your server and you need to know where it is located. If you are unsure of the exact path consult your ISP or server administrator.'),
+    '#description' => t('ImageMagick is a collection of standalone programs used to manipulate images. To use it, it must be installed on your server and you need to know where the programs are located. If you are unsure of the exact paths consult your ISP or server administrator.'),
   );
 
   $form['imageapi_imagemagick_binary']['version'] = array('#weight' => -1);
@@ -44,10 +44,19 @@ function imageapi_imagemagick_settings_f
     '#title' => t('Path to the "convert" binary'),
     '#default_value' => variable_get('imageapi_imagemagick_convert', '/usr/bin/convert'),
     '#required' => TRUE,
-    '#description' => t('Specify the complete path to the ImageMagic <kbd>convert</kbd> binary. For example: <kbd>/usr/bin/convert</kbd> or <kbd>C:\Program Files\ImageMagick-6.3.4-Q16\convert.exe</kbd>'),
+    '#description' => t('Specify the complete path to the ImageMagick <kbd>convert</kbd> binary. For example: <kbd>/usr/bin/convert</kbd> or <kbd>C:\Program Files\ImageMagick-6.3.4-Q16\convert.exe</kbd>'),
     '#element_validate' => array('imageapi_imagemagick_validate_path'),
   );
 
+  $form['imageapi_imagemagick_binary']['imageapi_imagemagick_identify'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path to the "identify" binary'),
+    '#default_value' => variable_get('imageapi_imagemagick_identify', '/usr/bin/identify'),
+    '#required' => TRUE,
+    '#description' => t('Specify the complete path to the ImageMagick <kbd>identify</kbd> binary. This is usually in the same directory as the <kbd>convert</kbd> binary.'),
+    '#element_validate' => array('imageapi_imagemagick_validate_path'),
+   );
+
   $form['imageapi_imagemagick_binary']['imageapi_imagemagick_debugging'] = array(
     '#type' => 'checkbox',
     '#title' => t('Display debugging information'),
@@ -101,8 +110,28 @@ function imageapi_imagemagick_image_open
   return $image;
 }
 
-function imageapi_imagemagick_image_close($image, $dst) {
-  return _imageapi_imagemagick_convert($image->source, $dst, $image->ops);
+/**
+ * Imagemagick helper to write an image resource to a destination file.
+ *
+ * @param $image
+ *   An image object.
+ * @param $destination
+ *   A string file path where the image should be saved.
+ * @return
+ *   TRUE or FALSE, based on success.
+ *
+ * @see imageapi_image_close()
+ */
+function imageapi_imagemagick_image_close($image, $destination) {
+  // Functions that operate on images can set the desired mime type of the
+  // image. Here we obtain the image type, so it can be passed onto 
+  // the convert binary by _imageapi_imagemagick_convert()
+  $type = '';
+  if (!strncmp($image->info['mime_type'], 'image/', 6)) {
+    $type = substr($image->info['mime_type'], 6);
+  }
+
+  return _imageapi_imagemagick_convert($image->source, $destination, $image->ops, $type);
 }
 
 function imageapi_imagemagick_image_crop(&$image, $x, $y, $width, $height) {
@@ -142,21 +171,92 @@ function imageapi_imagemagick_image_desa
 }
 
 /**
- * Calls the convert executable with the specified filter.
+ * Get details about an image using the Imagemagick identify binary.
+ *
+ * Imagemagick supports a number of file formats; see
+ * http://www.imagemagick.org/script/formats.php
+ * However, some of these formats may not be compiled into imagemagick on 
+ * your system. To se the list of formats supported on your system, enter:
+ *
+ * identify -list format
+ *
+ * at a command line prompt.
+ * 
+ * @param $image
+ *   An image object.
+ * @return
+ *   FALSE, if the file could not be found or is not an image. Otherwise, a
+ *   keyed array containing information about the image:
+ *    'width'     - Width in pixels.
+ *    'height'    - Height in pixels.
+ *    'extension' - Commonly used file extension for the image.
+ *    'mime_type' - MIME type, e.g. 'image/jpeg', 'image/gif', 'image/png'.
+ *    'file_size' - File size in bytes.
  */
-function _imageapi_imagemagick_convert($source, $dest, $args) {
-  $args['quality'] = '-quality '. escapeshellarg(variable_get('imageapi_imagemagick_quality', 75));
+function imageapi_imagemagick_image_get_info($image) {
+  $info = FALSE;
+  // From http://www.imagemagick.org/script/escape.php :
+  // - "%w": image width in pixels
+  // - "%h": image height in pixels
+  // - "%m": "magick" (i.e. extension)
+  _imageapi_imagemagick_identify_exec("-format \"%w %h %m\" " . escapeshellarg($image->source), $output, $errors);
+  $results = explode(' ', $output);
+  if (count($results)) {
+    $info = array('width' => $results[0],
+                  'height' => $results[1],
+                  'extension' => strtolower($results[2]),
+                  'file_size' => @filesize($image->source),
+                  'mime_type' => file_get_mimetype($image->source));
+  }
+  return $info;
+}
+
+/**
+ * Calls the convert binary with the specified filter.
+ *
+ * @param $image
+ *   An image object.
+ * @param $destination
+ *   A string file path where the image should be saved.
+ * @param $ops
+ *   An array of operators to pass to the convert binary.
+ * @param $type
+ *   A string containing the mime subtype, e.g. "jpeg" or "png".
+ *
+ * @return
+ *   TRUE or FALSE, based on success.
+ */
+function _imageapi_imagemagick_convert($source, $destination, $ops, $type='') {
+  $ops['quality'] = '-quality '. escapeshellarg(variable_get('imageapi_imagemagick_quality', 75));
+
+  // When an image contains more than one layer, ImageMagick normally converts
+  // to more than one image. But we don't want this, so we pass the -append
+  // argument. This has no effect on single-layered images.
+  $ops['append'] = '-append';
+
+  // If a type is specified, this is prepended to the destination
+  $type_dest = isset($type) ? $type . ':' . $destination : $destination;
+
   // To make use of ImageMagick 6's parenthetical command grouping we need to make
-  // the $source image the first parameter and $dest the last.
+  // the $source image the first parameter and $destination the last.
   // See http://www.imagemagick.org/Usage/basics/#cmdline for more info.
-  $command = escapeshellarg($source) .' '. implode(' ', $args) .' '. escapeshellarg($dest);
+  $command = escapeshellarg($source . '[0]') .' '. implode(' ', $ops) .' '. escapeshellarg($type_dest);
 
   if (0 != _imageapi_imagemagick_convert_exec($command, $output, $errors)) {
     return FALSE;
   }
-  return file_exists($dest);
+  return file_exists($destination);
 }
 
+/**
+ * Check whether a path exists and is executable.
+ * 
+ * @param $path
+ *   The path to check.
+ *
+ * @return
+ *   An array of errors. This is empty if the path exits and is executable.
+ */
 function _imageapi_imagemagick_check_path($path) {
   $errors = array();
   if (!is_file($path)) {
@@ -171,9 +271,64 @@ function _imageapi_imagemagick_check_pat
   return $errors;
 }
 
-function _imageapi_imagemagick_convert_exec($command_args, &$output, &$errors) {
+/**
+ * Calls the convert binary with the specified arguments.
+ *
+ * @param $args
+ *   Arguments to the convert binary.
+ * @param $output
+ *   An array of operators to pass to the convert binary.
+ * @param $errors
+ *   A string containing the mime subtype, e.g. "jpeg" or "png".
+ *
+ * @return
+ *   The exit code from the binary, of FALSE, if the convert binary 
+ *   is not executable.
+ */
+function _imageapi_imagemagick_convert_exec($args, &$output, &$errors) {
   $convert_path = variable_get('imageapi_imagemagick_convert', '/usr/bin/convert');
-  if ($errors = _imageapi_imagemagick_check_path($convert_path)) {
+  return _imageapi_imagemagick_exec($convert_path, $args, $output, $errors);
+}
+
+/**
+ * Calls the identify binary with the specified arguments.
+ *
+ * @param $args
+ *   Arguments to the convert binary.
+ * @param $output
+ *   An array of operators to pass to the convert binary.
+ * @param $errors
+ *   A string containing the mime subtype, e.g. "jpeg" or "png".
+ *
+ * @return
+ *   The exit code from the binary, of FALSE, if the identify binary 
+ *   is not executable.
+ */
+function _imageapi_imagemagick_identify_exec($args, &$output, &$errors) {
+  $identify_path = variable_get('imageapi_imagemagick_identify', '/usr/bin/identify');
+  return _imageapi_imagemagick_exec($identify_path, $args, $output, $errors);
+}
+
+/**
+ * Calls a binary with the specified arguments.
+ * 
+ * Errors are reported using watchdog, and debugging information is 
+ * displayed, if imageapi_imagemagick_debugging is TRUE.
+ *
+ * @param $command_path
+ *   Full path to the binary.
+ * @param $command_args
+ *   An argument string to pass to the binary.
+ * @param $output
+ *   String containing the standard output from the binary.
+ * @param $errors
+ *   String containing the standard error from the binary.
+ *
+ * @return
+ *   The exit code from the binary, of FALSE, if the binary is not executable.
+ */
+function _imageapi_imagemagick_exec($command_path, $command_args, &$output, &$errors) {
+  if ($errors = _imageapi_imagemagick_check_path($command_path)) {
     watchdog('imageapi imagemagick', '!errors', array('!errors' => implode('<br />', $errors)), WATCHDOG_ERROR);
     return FALSE;
   }
@@ -187,7 +342,7 @@ function _imageapi_imagemagick_convert_e
     // 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'. escapeshellarg($drupal_path) .' /B '. escapeshellarg($convert_path);
+    $convert_path = 'start "window title" /D'. escapeshellarg($drupal_path) .' /B '. escapeshellarg($command_path);
   }
 
   $descriptors = array(
@@ -195,7 +350,7 @@ function _imageapi_imagemagick_convert_e
     1 => array('pipe', 'w'), // stdout
     2 => array('pipe', 'w')  // stderr
   );
-  if ($h = proc_open($convert_path .' '. $command_args, $descriptors, $pipes, $drupal_path)) {
+  if ($h = proc_open($command_path .' '. $command_args, $descriptors, $pipes, $drupal_path)) {
     $output = '';
     while (!feof($pipes[1])) {
       $output .= fgets($pipes[1]);
@@ -208,7 +363,7 @@ function _imageapi_imagemagick_convert_e
 
     // Display debugging information to authorized users.
     if (variable_get('imageapi_imagemagick_debugging', FALSE) && user_access('administer site configuration')) {
-      drupal_set_message(t('ImageMagick command: @command', array('@command' => $convert_path .' '. $command_args)));
+      drupal_set_message(t('ImageMagick command: @command', array('@command' => $command_path .' '. $command_args)));
       drupal_set_message(t('ImageMagick output: @output', array('@output' => $output)));
     }
 
