? image.imagecache_integration.20100604b.patch
? imagecache_integration.png
Index: image.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/image/image.admin.inc,v
retrieving revision 1.9
diff -u -p -r1.9 image.admin.inc
--- image.admin.inc	13 Oct 2009 08:38:52 -0000	1.9
+++ image.admin.inc	4 Jun 2010 08:19:45 -0000
@@ -60,6 +60,18 @@ function image_admin_settings() {
     );
   }
 
+  // Allow for third-party modules (imagecache) to add to the 
+  // available preset operations. 
+  // This will include our own image.module built-in actions also.
+  $operations = module_invoke_all('image_operations', TRUE);
+  // Convert the operation info to a select list.
+  $operation_options = array();
+  foreach($operations as $operation_id => $operation) {
+    $operation_options[$operation_id] = $operation['name']; 
+  }
+  // Note that our own actions get special treatment - the height/width settings.
+  $our_operations = image_image_operations();
+
   foreach ($sizes as $key => $size) {
     $form['image_sizes'][$key]['label'] = array(
       '#type' => 'textfield',
@@ -77,20 +89,33 @@ function image_admin_settings() {
     $form['image_sizes'][$key]['operation'] = array(
       '#type' => 'select',
       '#default_value' => $size['operation'],
-      '#options' => array('scale' => t('Scale image'), 'scale_crop' => t('Scale and crop image')),
-    );
-    $form['image_sizes'][$key]['width'] = array(
-      '#type' => 'textfield',
-      '#default_value' => $size['width'],
-      '#size' => 5,
-      '#maxlength' => 5,
-    );
-    $form['image_sizes'][$key]['height'] = array(
-      '#type' => 'textfield',
-      '#default_value' => $size['height'],
-      '#size' => 5,
-      '#maxlength' => 5,
+      '#options' => $operation_options,
     );
+    // Only show size fields for our own operations.
+    if (empty($size['operation']) || in_array($size['operation'], array_keys($our_operations))) {
+      $form['image_sizes'][$key]['width'] = array(
+        '#type' => 'textfield',
+        '#default_value' => @$size['width'],
+        '#size' => 5,
+        '#maxlength' => 5,
+      );
+      $form['image_sizes'][$key]['height'] = array(
+        '#type' => 'textfield',
+        '#default_value' => @$size['height'],
+        '#size' => 5,
+        '#maxlength' => 5,
+      );
+    }
+    else {
+      // Allow the other module to put something informative here instead of the dimensions.
+      $operation = @$operations[$size['operation']];
+      if (!empty($operation['extra'])) {
+        $form['image_sizes'][$key]['extra'] = array(
+          '#type' => 'markup',
+          '#value' => $operation['extra'],
+        );
+      }
+    }
     $form['image_sizes'][$key]['link'] = array(
       '#type' => 'select',
       '#default_value' => $size['link'],
@@ -107,14 +132,25 @@ function image_admin_settings() {
 
 /**
  * Form validation handler for image admin settings form.
+ * 
+ * CHANGELOG - this was using $form[...]['#value'] where it should have been
+ * using $form_state['values']. Changed it to behave normally, but unsure if the
+ * previous method was intentional. - dman
  */
 function image_admin_settings_validate($form, &$form_state) {
   // Check that the sizes provided have the required amount of information.  
+  
+  $our_operation_ids = array_keys(image_image_operations());
+  $image_sizes = $form_state['values']['image_sizes'];
   foreach (element_children($form['image_sizes']) as $key) {
-    // If there's a label they must provide at either a height or width.
-    if ($key != IMAGE_ORIGINAL && !empty($form['image_sizes'][$key]['label']['#value'])) {
-      if (empty($form['image_sizes'][$key]['width']['#value']) && empty($form['image_sizes'][$key]['height']['#value'])) {
-        form_set_error("image_sizes][$key][width", t('You must specify width, height or both dimensions.'));
+    // Only validate our own own known operations, 
+    // allow for other operations to be available without defined dimensions
+    if (in_array($image_sizes[$key]['operation'], $our_operation_ids)) {
+      // If there's a label they must provide at either a height or width.
+      if ($key != IMAGE_ORIGINAL && !empty($image_sizes[$key]['label'])) {
+        if (empty($image_sizes[$key]['width']) && empty($image_sizes[$key]['height'])) {
+          form_set_error("image_sizes][$key][width", t('You must specify width, height or both dimensions.'));
+        }
       }
     }
   }
@@ -171,7 +207,7 @@ function image_admin_settings_submit($fo
     else if (isset($form_state['values']['image_sizes'][$key]) && isset($old_sizes[$key])) {
       // Did the operation, height or width change?
       foreach (array('operation', 'height', 'width') as $field) {
-        $rebuild |= ($form_state['values']['image_sizes'][$key][$field] != $old_sizes[$key][$field]);
+        $rebuild |= (@$form_state['values']['image_sizes'][$key][$field] != @$old_sizes[$key][$field]);
       }
     }
   }
@@ -186,12 +222,22 @@ function image_admin_settings_submit($fo
 
 function theme_image_settings_sizes_form($form) {
   $header = array(t('Label'), t('Operation'), t('Width'), t('Height'), t('Link'));
+
   foreach (element_children($form) as $key) {
     $row = array();
     $row[] = drupal_render($form[$key]['label']);
     $row[] = drupal_render($form[$key]['operation']);
-    $row[] = drupal_render($form[$key]['width']);
-    $row[] = drupal_render($form[$key]['height']);
+    // If it's a third-party action, don't show the dimensions, show its provided info instead.
+    if (!empty($form[$key]['extra'])) {
+      $row[] = array(
+        'colspan' => 2,
+        'data' => drupal_render($form[$key]['extra']),
+      );
+    }
+    else {
+      $row[] = drupal_render($form[$key]['width']);
+      $row[] = drupal_render($form[$key]['height']);
+    }
     $row[] = drupal_render($form[$key]['link']);
     $rows[] = $row;
   }
Index: image.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/image/Attic/image.module,v
retrieving revision 1.322
diff -u -p -r1.322 image.module
--- image.module	13 Sep 2009 20:21:04 -0000	1.322
+++ image.module	4 Jun 2010 08:19:45 -0000
@@ -784,6 +784,67 @@ function _image_check_settings() {
 }
 
 /**
+ * Implementation of (our own) hook_image_operations(). 
+ * 
+ * Declare the operations we make available for use as derivative sizes.
+ * Returns an array of operation definitions, keyed by operation id.
+ * 
+ * The operation definition may contain the keys:
+ *   'name' => "Human-readable name for this action",   
+ *   'module' => "Name of the module that provides the operation"
+ *   'callback' => "Name of the function that performs the operation"
+ *   'extra'   => "If present, it may provide some additional information about
+ * the operation, such as a link to its configuration page"
+ * 
+ * See _image_build_derivative() for the "callback" function signature.
+ * 
+ * @return an array of image operation definitions.
+ * 
+ * @see image_admin_settings()
+ */
+function image_image_operations() {
+  $operations = array(
+    'scale' => array(
+      'name' => t('Scale image'),
+      'module' => 'image',
+      'callback' => '_image_build_derivative',
+    ), 
+    'scale_crop' => array(
+      'name' => t('Scale and crop image'),
+      'module' => 'image',
+      'callback' => '_image_build_derivative',
+    ),
+  );
+  return $operations;
+}
+
+/**
+ * Generate a single image derivative. Invoked as a callback from within
+ * _image_build_derivatives().
+ *
+ * @param $original_path
+ *   Source image
+ * @param $destination 
+ *   Save image as
+ * @param $derivative_info 
+ *   An array of data that image.module settings form may save. Normally
+ * this includes the derivative name, operation id, and width and height.
+ * $derivative_info['operation'] will be of the form 'imagecache-n' where n is a
+ * preset id that we will build
+ * 
+ * @see _image_build_derivatives()
+ */
+function _image_build_derivative($original_path, $destination, $derivative_info = array()) {
+  switch ($derivative_info['operation']) {
+    case 'scale':
+      return image_scale($original_path, $destination, $derivative_info['width'], $derivative_info['height']);
+    case 'scale_crop':
+      return image_scale_and_crop($original_path, $destination,  $derivative_info['width'], $derivative_info['height']);
+  }
+  return FALSE;
+}
+
+/**
  * Determine which sizes of derivative images need to be built for this image.
  *
  * @param $image_path
@@ -806,6 +867,11 @@ function image_get_derivative_sizes($ima
     if ($key == IMAGE_ORIGINAL) {
       continue;
     }
+    if ($size['operation'] != 'scale' && $size['operation'] != 'scale_crop') {
+      // Not one of our own processess, Always rebuild.
+      $sizes[$key] = $size;
+      continue;
+    }
 
     // If the original isn't bigger than the requested size then there's no
     // need to resize it.
@@ -844,24 +910,34 @@ function _image_build_derivatives($node,
 
   // Resize for the necessary sizes.
   $image_info = image_get_info($original_path);
+  $operations = module_invoke_all('image_operations');
   foreach ($needed_sizes as $key => $size) {
     $destination = _image_filename($original_path, $key, $temp);
 
     $status = FALSE;
-    switch ($size['operation']) {
-      // Depending on the operation, the image will be scaled or resized & cropped
-      case 'scale':
-        $status = image_scale($original_path, $destination, $size['width'], $size['height']);
-        break;
-
-      case 'scale_crop':
-        $status = image_scale_and_crop($original_path, $destination,  $size['width'], $size['height']);
-        break;
+    // Depending on the operation, different callbacks will be invoked.
+    // Normally, for scale or scale_crop, that will mean calling our own 
+    // callbacks declared in hook_image_operations() and executed in 
+    // _image_build_derivative().
+
+    $operation = $operations[$size['operation']];
+    // Be very careful not to die if the needed module or setting has gone missing.
+    if (empty($operation)) {
+      // The module that provides this operation is now unavailable?
+      watchdog('image', 'When building image derivative %key, it appears that the image operation %operation is invalid. Perhaps it depends on an unavailable module. Not building this derivative image.', array('%operation_name' => $operation['name'], '%key' => $key), WATCHDOG_ERROR );
+      $status = FALSE;
+    }
+    if (!empty($operation['callback']) && function_exists($operation['callback'])) {
+      $status = $operation['callback']($original_path, $destination, $size);
+    }
+    else {
+      watchdog('image', 'When building image derivative %key, it appears that the image operation %operation is invalid. Could not access the callback function [%operation_callback] to process the image. Not building this derivative image.', array('%key' => $key, '%operation_name' => $operation['name'], '%operation_callback' => $operation['callback']), WATCHDOG_ERROR);
+      $status = FALSE;
     }
 
     if (!$status) {
       drupal_set_message(t('Unable to create scaled %label image.', array('%label' => $size['label'])), 'error');
-      return FALSE;
+      //return FALSE; // one failure may not mean that we should give up entirely.
     }
     // Set standard file permissions for webserver-generated files
     @chmod($destination, 0664);
