Index: image.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/image/image.admin.inc,v retrieving revision 1.9.2.2 diff -u -p -r1.9.2.2 image.admin.inc --- image.admin.inc 3 Aug 2010 17:43:00 -0000 1.9.2.2 +++ image.admin.inc 27 Aug 2010 13:52:38 -0000 @@ -60,6 +60,20 @@ 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. + // @see image_image_operations() + $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']; + if ($operation['module'] != 'image') { + $operation_options[$operation_id] .= ' (' . $operation['module'] . ')'; + } + } + foreach ($sizes as $key => $size) { $form['image_sizes'][$key]['label'] = array( '#type' => 'textfield', @@ -77,20 +91,34 @@ 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 operations that ask for it + if (empty($size['operation']) || $operations[$size['operation']]['needs_dimensions']) { + $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, + ); + } + elseif (isset($operations[$size['operation']])) { + // Allow the providing 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'], @@ -110,12 +138,21 @@ function image_admin_settings() { */ function image_admin_settings_validate($form, &$form_state) { // Check that the sizes provided have the required amount of information. + $operations = module_invoke_all('image_operations', TRUE); $image_sizes = $form_state['values']['image_sizes']; foreach (element_children($image_sizes) as $key) { - // 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.')); + $size = $image_sizes[$key]; + $operation = $operations[$size['operation']]; + // If there's a label, may be required to provide either a height or width. + + // Note, this validation is weak here now, as it will only validate when + // all inputs are as expected. + // Checking only 'needs_dimensions' or only width & height makes it + // impossible to switch operation types and still validate without a form + // rebuild (which I cannot force from here). + if ($key != IMAGE_ORIGINAL && !empty($size['label']) && !empty($operation['needs_dimensions']) && isset($size['width']) && isset($size['height'])) { + if (empty($size['width']) && empty($size['height'])) { + form_set_error("image_sizes][$key][label", t('You must specify width, height or both dimensions.')); } } } @@ -172,7 +209,9 @@ 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]); + if (isset($form_state['values']['image_sizes'][$key][$field]) && isset($old_sizes[$key][$field]) && ($form_state['values']['image_sizes'][$key][$field] != $old_sizes[$key][$field])) { + $rebuild = TRUE; + } } } } @@ -191,8 +230,18 @@ function theme_image_settings_sizes_form $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.2.4 diff -u -p -r1.322.2.4 image.module --- image.module 18 Aug 2010 16:40:06 -0000 1.322.2.4 +++ image.module 27 Aug 2010 13:52:39 -0000 @@ -787,6 +787,73 @@ 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_scale() 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', + 'needs_dimensions' => TRUE, + // This indicates that basic width x height fields should be displayed + // on the configuration form + ), + 'scale_crop' => array( + 'name' => t('Scale and crop image'), + 'module' => 'image', + 'callback' => '_image_build_derivative_scale_and_crop', + 'needs_dimensions' => TRUE, + ), + ); + return $operations; +} + +/** + * Generate a single image derivative, using the 'scale' operation. Invoked as a + * named 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_scale($original_path, $destination, $derivative_info = array()) { + return image_scale($original_path, $destination, $derivative_info['width'], $derivative_info['height']); +} + +/** + * Generate a single image derivative, using the 'scale and crop' operation. + * Invoked as a named callback from within _image_build_derivatives(). + */ +function _image_build_derivative_scale_and_crop($original_path, $destination, $derivative_info = array()) { + return image_scale_and_crop($original_path, $destination, $derivative_info['width'], $derivative_info['height']); +} + +/** * Determine which sizes of derivative images need to be built for this image. * * @param $image_path @@ -810,6 +877,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. @@ -849,24 +921,38 @@ 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_scale() _image_build_derivative_scale_and_crop(). + + $operation = $operations[$size['operation']]; + // Be very careful not to die if the needed module or setting is 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; + } + else { + 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; + // One failure may not mean that we should give up entirely. + // Make the other derivatives anyway. } // Set standard file permissions for webserver-generated files @chmod($destination, 0664);