You are here

imagecache.module in ImageCache 5

Same filename and directory in other branches
  1. 5.2 imagecache.module
  2. 6.2 imagecache.module

Dynamic image resizer and image cacher.

Imagecache allows you to setup specialized identifiers for dynamic image processing and caching. It abuses the rewrite rules used for drupal's clean URLs to provide dynamic image generation.

URLs are of the form: files/imagecache/<preset>/path

Notes: To add a new handler, add fields and select option to _imagecache_actions_form; add handling code to imagecache_cache

File

imagecache.module
View source
<?php

/**
 * @file
 * Dynamic image resizer and image cacher.
 *
 * Imagecache allows you to setup specialized identifiers for dynamic image
 * processing and caching. It abuses the rewrite rules used for drupal's clean
 * URLs to provide dynamic image generation.
 * 
 * URLs are of the form: files/imagecache/<preset>/path
 * 
 * Notes:
 *   To add a new handler,
 *     add fields and select option to _imagecache_actions_form;
 *     add handling code to imagecache_cache
 * 
 */

/**
 * Implementation of hook_perm().
 */
function imagecache_perm() {
  return array(
    'administer imagecache',
    'flush imagecache',
  );
}

/**
 * Implementation of hook_menu().
 */
function imagecache_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => file_directory_path() . '/imagecache',
      'callback' => 'imagecache_cache',
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/settings/imagecache',
      'title' => t('Image cache'),
      'description' => t('Configure rulesets and actions for imagecache.'),
      'access' => user_access('administer imagecache'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'imagecache_admin',
      ),
    );
  }
  return $items;
}

/**
 * Implementation of hook_requirements().
 */
function imagecache_requirements($phase) {
  $requirements = array();

  // Ensure translations don't break at install time.
  $t = get_t();
  if ($phase == 'runtime') {

    // Clean URLS.
    if (!variable_get('clean_url', 0)) {
      $requirements['clean_urls'] = array(
        'title' => $t('Clean URLs'),
        'value' => $t('Not enabled'),
        'severity' => REQUIREMENT_ERROR,
        'description' => $t('Imagecache will not operate properly if <a href="!url">Clean URLs</a> is not enabled on your site.', array(
          '!url' => url('admin/settings/clean-urls'),
        )),
      );
    }

    // Check for an image library.
    if (count(image_get_available_toolkits()) == 0) {
      $requirements['image_toolkits'] = array(
        'title' => $t('Image Toolkit'),
        'value' => $t('No image toolkits available'),
        'severity' => REQUIREMENT_ERROR,
        'description' => $t('Imagecache requires an imagetoolkit such as <a href="http://php.net/gd">GD2</a> or <a href="http://www.imagemagick.org">Imagemagick</a> be installed on your server.'),
      );
    }

    // Check for public files.
    if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PRIVATE) {
      $requirements['file_system'] = array(
        'title' => $t('File Download Method'),
        'value' => $t('Private Downloads'),
        'severity' => REQUIREMENT_ERROR,
        'description' => $t('Imagecache will not operate properly using Private Files. Please enable <a href="!url">Public File Transfer</a>.', array(
          '!url' => url('admin/settings/file-system'),
        )),
      );
    }

    // Check for JPEG/PNG/GIF support.
    if ('gd' == image_get_toolkit()) {
      foreach (array(
        'gif',
        'jpeg',
        'png',
      ) as $format) {
        if (!function_exists('imagecreatefrom' . $format)) {
          $requirements['gd_' . $format] = array(
            'title' => $t('GD !format Support', array(
              '!format' => drupal_ucfirst($format),
            )),
            'value' => $t('Not installed'),
            'severity' => REQUIREMENT_INFO,
            'description' => $t('PHP was not compiled with %format support. Imagecache will not be able to process %format images.', array(
              '%format' => $format,
            )),
          );
        }
      }
    }
  }
  return $requirements;
}
function imagecache_cache() {
  $args = func_get_args();
  $preset = array_shift($args);
  $preset_id = _imagecache_preset_load_by_name($preset);
  if (!$preset_id) {
    watchdog('imagecache', t('Preset(%p) not found', array(
      '%p' => $preset,
    )), WATCHDOG_ERROR);
    header('HTTP/1.0 404 Not Found');
    exit;
  }

  // Verify that the source exists, if not exit. Maybe display a missing image.
  $src = file_create_path(implode('/', $args));
  if (!is_file($src)) {
    watchdog('imagecache', t('Source(%s) not found.', array(
      '%s' => $src,
    )), WATCHDOG_ERROR);
    header('HTTP/1.0 404 Not Found');
    exit;
  }

  // Build the destination folder tree if it doesn't already exists,
  // and make sure it is writable.
  $dst = 'imagecache/' . $preset . '/' . $src;

  // Build the destination folder tree if it doesn't already exists.
  if (!file_check_directory(file_create_path($dst))) {
    $folders = explode("/", _imagecache_strip_file_directory(dirname($dst)));
    foreach ($folders as $folder) {
      $tpath[] = $folder;
      $checkpath = implode("/", $tpath);
      if (!file_check_directory(file_create_path($checkpath), FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
        watchdog('imagecache', t('Cannot create/fix dir(%d).', array(
          '%d' => $checkpath,
        )), WATCHDOG_ERROR);
        header("HTTP/1.0 500 Internal Server Error");
        exit;
      }
    }
  }

  // Prepend presetname to tmp file name to prevent namespace clashes when
  // multiple presets for the same image are called in rapid succession.
  $tmp = file_directory_temp() . '/tmp_imagecache_' . md5($src) . '_' . $preset . '_' . basename($src);
  register_shutdown_function('file_delete', $tmp);

  // Check if file exists to prevent multiple apache children from trying to generate.
  if (is_file($tmp)) {
    watchdog('imagecache', t('tmp file(%t) already exists.', array(
      '%t' => $tmp,
    )), WATCHDOG_NOTICE);

    // non-caching redirect to self, we hope the processing has finished by the time we come back.
    // 307 Temporary Redirect
    header("Location: " . $_SERVER['REQUEST_URI'], TRUE, 307);
    exit;
  }

  // copy source to a temporary file we will use to apply the imagecache actions to.
  if (!file_copy($src, $tmp)) {
    watchdog('imagecache', t('Could not copy src(%s) to tmp(%t).', array(
      '%s' => $src,
      '%t' => $tmp,
    )), WATCHDOG_ERROR);
    header("HTTP/1.0 500 Internal Server Error");
    exit;
  }
  $actions = _imagecache_actions_get_by_presetid($preset_id);
  foreach ($actions as $action) {
    $size = getimagesize($tmp);
    if (empty($action['data']['height'])) {
      $action['data']['height'] = round($size[1] * ($action['data']['width'] / $size[0]));
    }
    if (empty($action['data']['width'])) {
      $action['data']['width'] = $size[0] * ($action['data']['height'] / $size[1]);
    }
    $new_width = _imagecache_filter('width', $action['data']['width'], $size[0], $size[1]);
    $new_height = _imagecache_filter('height', $action['data']['height'], $size[0], $size[1]);
    foreach ($action['data'] as $key => $value) {
      $action['data'][$key] = _imagecache_filter($key, $value, $size[0], $size[1], $new_width, $new_height);
    }
    switch ($action['data']['function']) {
      case 'resize':
        if (!image_resize($tmp, $tmp, $action['data']['width'], $action['data']['height'])) {
          watchdog('imagecache', t('Imagecache resize action ID %id failed.', array(
            '%id' => $action['actionid'],
          )), WATCHDOG_ERROR);
        }
        break;
      case 'scale':
        if ($action['data']['fit'] == 'outside' && $action['data']['width'] && $action['data']['height']) {
          $ratio = $size[0] / $size[1];
          $new_ratio = $action['data']['width'] / $action['data']['height'];
          $action['data']['width'] = $ratio > $new_ratio ? 0 : $action['data']['width'];
          $action['data']['height'] = $ratio < $new_ratio ? 0 : $action['data']['height'];
        }

        // Set impossibly large values if the width and height aren't set.
        $action['data']['width'] = $action['data']['width'] ? $action['data']['width'] : 9999999;
        $action['data']['height'] = $action['data']['height'] ? $action['data']['height'] : 9999999;
        if (!image_scale($tmp, $tmp, $action['data']['width'], $action['data']['height'])) {
          watchdog('imagecache', t('Imagecache scale action ID %id failed.', array(
            '%id' => $action['actionid'],
          )), WATCHDOG_ERROR);
        }
        break;
      case 'crop':
        if (!image_crop($tmp, $tmp, $action['data']['xoffset'], $action['data']['yoffset'], $action['data']['width'], $action['data']['height'])) {
          watchdog('imagecache', t('Imagecache crop action ID %id failed.', array(
            '%id' => $action['actionid'],
          )), WATCHDOG_ERROR);
        }
        break;
    }
  }

  // move the temporary file to it's final destination.
  $final_path = file_create_path($dst);
  if (!file_move($tmp, $final_path)) {
    watchdog('imagecache', t('Could not move tmp(%t) to dst(%d).', array(
      '%d' => $dst,
      '%t' => $tmp,
    )), WATCHDOG_ERROR);
    header("HTTP/1.0 500 Internal Server Error");
    exit;
  }

  // Serve it up...
  $size = getimagesize($final_path);
  file_transfer($final_path, array(
    'Content-Type: ' . mime_header_encode($size['mime']),
    'Content-Length: ' . filesize($final_path),
  ));
  exit;
}

/**
 * Remove a possible leading file directory path from the given path.
 */
function _imagecache_strip_file_directory($path) {
  $dirpath = file_directory_path();
  $dirlen = strlen($dirpath);
  if (substr($path, 0, $dirlen + 1) == $dirpath . '/') {
    $path = substr($path, $dirlen + 1);
  }
  return $path;
}

/**
 * Implementation of hook_field_formatter_info().
 */
function imagecache_field_formatter_info() {
  $rules = _imagecache_get_presets();
  foreach ($rules as $ruleid => $rulename) {
    $formatters[$rulename] = array(
      'label' => t('!rulename as image', array(
        '!rulename' => $rulename,
      )),
      'field types' => array(
        'image',
      ),
    );
    $formatters[$rulename . '_linked'] = array(
      'label' => t('!rulename as link', array(
        '!rulename' => $rulename,
      )),
      'field types' => array(
        'image',
      ),
    );
  }
  return $formatters;
}

/**
 * Implementation of hook_field_formatter().
 */
function imagecache_field_formatter($field, $item, $formatter) {
  if (empty($item['fid'])) {
    return '';
  }

  // Views does not load the file for us, while CCK display fields does.
  if (!isset($item['filepath'])) {
    $file = _imagecache_file_load($item['fid']);
    $item = array_merge($item, $file);
  }
  $rules = _imagecache_get_presets();
  $formatter_check = preg_replace('/_linked$/', '', $formatter);
  if (in_array($formatter_check, (array) $rules)) {
    return theme('imagecache_formatter', $field, $item, $formatter);
  }
}
function _imagecache_file_load($fid = NULL) {

  // Don't bother if we weren't passed an fid.
  if (isset($fid) && is_numeric($fid)) {
    $result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid);
    $file = db_fetch_array($result);
  }
  return $file ? $file : array();
}
function _imagecache_get_presets($reset = FALSE) {
  static $presets = array();

  // Check caches if $reset is FALSE;
  if (!$reset) {
    if (!empty($presets)) {
      return $presets;
    }

    // Grab from cache saves building the array.
    // Plus it's a frequently used table.
    $cache = cache_get('imagecache:presets', 'cache');
    $presets = unserialize($cache->data);

    // If the preset is not an array, cache_clear_all has been called
    // there no/invalid data in the cache. Fall through and repopulate cache;
    if (is_array($presets)) {
      return $presets;
    }
  }

  // Load Data from the database on reset or if we get invalid data from the array.
  $presets = array();
  $result = db_query('SELECT presetid, presetname FROM {imagecache_preset} ORDER BY presetname');
  while ($row = db_fetch_array($result)) {
    $presets[$row['presetid']] = $row['presetname'];
  }
  cache_set('imagecache:presets', 'cache', serialize($presets));

  // Clear the content.module cache (refreshes the list of formatters provided by imagefield.module).
  if (module_exists('content')) {
    content_clear_type_cache();
  }
  return $presets;
}
function _imagecache_actions_get_by_presetid($presetid) {
  $actions = array();
  $result = db_query('SELECT actionid, weight, data FROM {imagecache_action} where presetid = %d order by weight', $presetid);
  while ($row = db_fetch_array($result)) {
    $row['data'] = unserialize($row['data']);
    $actions[$row['actionid']] = $row;
  }
  return $actions;
}

/**
 * Filter key word values such as 'top', 'right', 'center', and also percentages.
 * All returned values are in pixels relative to the passed in height and width.
 */
function _imagecache_filter($key, $value, $current_width, $current_height, $new_width = NULL, $new_height = NULL) {
  switch ($key) {
    case 'width':
      $value = _imagecache_percent_filter($value, $current_width);
      break;
    case 'height':
      $value = _imagecache_percent_filter($value, $current_height);
      break;
    case 'xoffset':
      $value = _imagecache_keyword_filter($value, $current_width, $new_width);
      break;
    case 'yoffset':
      $value = _imagecache_keyword_filter($value, $current_height, $new_height);
      break;
  }
  return $value;
}

/**
 * Accept a percentage and return it in pixels.
 */
function _imagecache_percent_filter($value, $current_pixels) {
  if (strpos($value, '%') !== FALSE) {
    $value = str_replace('%', '', $value) * 0.01 * $current_pixels;
  }
  return $value;
}

/**
 * Accept a keyword (center, top, left, etc) and return it as an offset in pixels.
 */
function _imagecache_keyword_filter($value, $current_pixels, $new_pixels) {
  switch ($value) {
    case 'top':
    case 'left':
      $value = 0;
      break;
    case 'bottom':
    case 'right':
      $value = $current_pixels - $new_pixels;
      break;
    case 'center':
      $value = $current_pixels / 2 - $new_pixels / 2;
      break;
  }
  return $value;
}
function imagecache_admin() {
  drupal_set_title('Imagecache administration');
  $form = array();
  $form['title'] = array(
    '#type' => 'markup',
    '#value' => t('Imagecache presets'),
  );
  $form['presets']['#tree'] = TRUE;
  $presets = _imagecache_get_presets();
  foreach ($presets as $presetid => $presetname) {
    $form['presets'][$presetid] = array(
      '#type' => 'fieldset',
      '#title' => $presetname,
      '#collapsible' => TRUE,
      '#collapsed' => arg(4) != $presetid,
    );
    $form['presets'][$presetid]['name'] = array(
      '#type' => 'textfield',
      '#title' => t('Preset namespace'),
      '#default_value' => $presetname,
      '#description' => t('String that will be used as an identifier in the url for this set of handlers. Final urls will look like http://example.com/files/imagecache/%namespace/&lt;path to orig&gt;', array(
        '%namespace' => $presetname,
      )),
    );
    $form['presets'][$presetid]['handlers'] = array(
      '#type' => 'fieldset',
      '#title' => t('Image handlers'),
    );
    $form['presets'][$presetid]['handlers']['#tree'] = FALSE;
    $form['presets'][$presetid]['handlers'] = _imagecache_actions_form($presetid);
    $form['presets'][$presetid]['ops']['#tree'] = FALSE;
    $form['presets'][$presetid]['ops']['update'] = array(
      '#type' => 'submit',
      '#name' => 'preset-op[' . $presetid . ']',
      '#value' => t('Update preset'),
    );
    $form['presets'][$presetid]['ops']['delete'] = array(
      '#type' => 'submit',
      '#name' => 'preset-op[' . $presetid . ']',
      '#value' => t('Delete preset'),
    );
    $form['presets'][$presetid]['ops']['flush'] = array(
      '#type' => 'submit',
      '#name' => 'preset-op[' . $presetid . ']',
      '#value' => t('Flush preset images'),
    );
  }
  $form['presets']['new'] = array(
    '#type' => 'fieldset',
    '#title' => t('New preset'),
    '#tree' => TRUE,
  );
  $form['presets']['new']['name'] = array(
    '#type' => 'textfield',
    '#size' => '64',
    '#title' => t('Preset namespace'),
    '#default_value' => '',
    '#description' => t('The namespace of an imagecache preset. It represents a series of actions to be performed when imagecache dynamically generates an image. This will also be used in the url for images. Please no spaces.'),
  );
  $form['presets']['new']['create'] = array(
    '#type' => 'submit',
    '#name' => 'preset-op[new]',
    '#value' => t('Create preset'),
    '#weight' => 10,
  );
  return $form;
}
function imagecache_admin_validate($form_id, $form_values) {
  if (is_array($_POST['preset-op'])) {
    foreach ($_POST['preset-op'] as $presetid => $op) {

      // Check for illegal characters in preset names
      if (preg_match('/[^0-9a-zA-Z_\\-]/', $form_values['presets'][$presetid]['name'])) {
        form_set_error('presets][' . $presetid . '][name', t('Please only use alphanumic characters, underscores (_), and hyphens (-) for preset names.'));
      }
    }
  }
}
function imagecache_admin_submit($form_id, $form_values) {
  if (is_array($_POST['preset-op'])) {
    foreach ($_POST['preset-op'] as $presetid => $op) {
      $presetid = check_plain($presetid);
      switch ($op) {
        case t('Create preset'):
          _imagecache_preset_create($form_values['presets']['new']['name']);
          break;
        case t('Update preset'):

          // Add new actions
          $newaction = $form_values['presets'][$presetid]['handlers']['newaction'];
          if ($newaction) {
            $action = array();
            $action['data'] = array(
              'function' => $newaction,
            );
            $action['presetid'] = $presetid;
            $action['weight'] = 0;
            _imagecache_action_create($action);
          }

          // Update existing actions
          foreach ($form_values['presets'][$presetid]['handlers'] as $actionid => $action) {
            if ($actionid != 'newaction') {
              $action['actionid'] = $actionid;
              $action['presetid'] = $presetid;
              $remove = $action['remove'];
              unset($action['remove']);
              $remove ? _imagecache_action_delete($action) : _imagecache_action_update($action);
            }
          }

          // Update the entire preset.
          _imagecache_preset_update($presetid, $form_values['presets'][$presetid]['name']);
          break;
        case t('Delete preset'):
          _imagecache_preset_delete($presetid, $form_values['presets'][$presetid]['name']);
          break;
        case t('Flush preset images'):
          _imagecache_preset_flush($presetid);
          break;
      }
    }
  }
}

/** 
 * Load a preset by id.
 * @param id
 *    Preset id.
 */
function _imagecache_preset_load($id) {
  $presets = _imagecache_get_presets();
  return $presets[$id];
}

/** 
 * Load a preset by name.
 *  @param name
 *    Preset name.
 */
function _imagecache_preset_load_by_name($name) {
  $presets = array_flip(_imagecache_get_presets());
  return $presets[$name];
}

/** 
 * Create a preset. 
 * @param name
 *    Name of the preset to be created.
 */
function _imagecache_preset_create($name) {
  $next_id = db_next_id('{imagecache_preset}_presetid');
  db_query('INSERT INTO {imagecache_preset} (presetid, presetname) VALUES (%d, \'%s\')', $next_id, $name);

  // Reset presets cache.
  _imagecache_get_presets(TRUE);
  $_REQUEST['destination'] = 'admin/settings/imagecache/preset/' . $next_id;
}

/**
 * Update a preset.
 * @param id
 *    Preset id.
 * @param name
 *    new name for the preset
 */
function _imagecache_preset_update($id, $name) {
  $name = check_plain($name);
  $id = (int) $id;
  _imagecache_preset_flush($id);
  db_query('UPDATE {imagecache_preset} SET presetname =\'%s\' WHERE presetid = %d', $name, $id);
  drupal_set_message(t('Updated preset "%name" (ID: @id)', array(
    '%name' => $name,
    '@id' => $id,
  )));

  // Reset presets cache.
  _imagecache_get_presets(TRUE);
  $_REQUEST['destination'] = 'admin/settings/imagecache/preset/' . $id;
}
function _imagecache_preset_delete($id, $name) {
  _imagecache_preset_flush($id);
  db_query('DELETE FROM {imagecache_action} where presetid = %d', $id);
  db_query('DELETE FROM {imagecache_preset} where presetid = %d', $id);
  drupal_set_message(t('Preset "%name" (ID: @id) deleted.', array(
    '%name' => $name,
    '@id' => $id,
  )));

  // Reset presets cache.
  _imagecache_get_presets(TRUE);
}

/**
 * Flush cached media for a preset.
 * @param id
 *   A preset id.
 */
function _imagecache_preset_flush($id) {
  if (user_access('flush imagecache')) {
    drupal_set_message(t('Flushed Preset Images (ID: @id)', array(
      '@id' => $id,
    )));
    $preset = _imagecache_preset_load($id);
    $presetdir = realpath(file_directory_path() . '/imagecache/' . $preset);
    if (is_dir($presetdir)) {
      _imagecache_recursive_delete($presetdir);
    }
  }
}

/**
 * Recursively delete all files and folders in the specified filepath, then 
 * delete the containing folder.
 *
 * Note that this only deletes visible files with write permission.
 *
 * @param string $path
 *   A filepath relative to file_directory_path.
 */
function _imagecache_recursive_delete($path) {
  $listing = $path . '/*';
  foreach (glob($listing) as $file) {
    if (is_file($file) === TRUE) {
      @unlink($file);
    }
    elseif (is_dir($file) === TRUE) {
      _imagecache_recursive_delete($file);
    }
  }
  @rmdir($path);
}
function _imagecache_action_create($action) {

  //debug_msg($action, 'action@create: ');
  $next_id = db_next_id('{imagecache_action}_actionid');
  db_query('INSERT INTO {imagecache_action} (actionid, presetid, weight, data) VALUES (%d, %d, %d, \'%s\')', $next_id, $action['presetid'], $action['weight'], serialize($action['data']));
}
function _imagecache_action_update($action) {

  //debug_msg($action, 'action@update');
  db_query('UPDATE {imagecache_action} SET weight = %d, data = \'%s\' WHERE actionid = %d', $action['weight'], serialize($action['data']), $action['actionid']);
}
function _imagecache_action_delete($action) {
  _imagecache_preset_flush($action['presetid']);
  db_query('DELETE FROM {imagecache_action} WHERE actionid = %d', $action['actionid']);
}
function _imagecache_actions_form($presetid) {
  $form = array();
  $actions = _imagecache_actions_get_by_presetid($presetid);
  foreach ($actions as $actionid => $action) {

    //debug_msg($action);
    $form[$actionid] = array(
      '#type' => 'fieldset',
      '#title' => t($action['data']['function']),
    );
    $form[$actionid]['data']['function'] = array(
      '#type' => 'hidden',
      '#value' => $action['data']['function'],
    );
    $form[$actionid]['weight'] = array(
      '#type' => 'weight',
      '#title' => t('Weight'),
      '#default_value' => $action['weight'],
    );
    switch ($action['data']['function']) {
      case 'scale':
        $helptext = array();
        $helptext['inside'] = t('<strong>Inside dimensions</strong>: Final dimensions will be less than or equal to the entered width and height. Useful for ensuring a maximum height and/or width.');
        $helptext['outside'] = t('<strong>Outside dimensions</strong>: Final dimensions will be greater than or equal to the entered width and height. Ideal for cropping the result to a square.');
        $description = '<ul><li>' . implode('</li><li>', $helptext) . '</li><ul>';
        $form[$actionid]['data']['fit'] = array(
          '#type' => 'select',
          '#title' => t('Scale to fit'),
          '#options' => array(
            'inside' => t('Inside dimensions'),
            'outside' => t('Outside dimensions'),
          ),
          '#default_value' => $action['data']['fit'],
          '#weight' => 1,
          '#description' => $description,
        );
      case 'resize':
        $form[$actionid]['data']['width'] = array(
          '#type' => 'textfield',
          '#title' => t('Width'),
          '#default_value' => $action['data']['width'],
          '#description' => t('Enter a width in pixels or as a percentage. i.e. 500 or 80%.'),
        );
        $form[$actionid]['data']['height'] = array(
          '#type' => 'textfield',
          '#title' => t('Height'),
          '#default_value' => $action['data']['height'],
          '#description' => t('Enter a height in pixels or as a percentage. i.e. 500 or 80%.'),
        );
        break;
      case 'crop':
        $form[$actionid]['data']['width'] = array(
          '#type' => 'textfield',
          '#title' => t('Width'),
          '#default_value' => $action['data']['width'],
          '#description' => t('Enter a width in pixels or as a percentage. i.e. 500 or 80%.'),
        );
        $form[$actionid]['data']['height'] = array(
          '#type' => 'textfield',
          '#title' => t('Height'),
          '#default_value' => $action['data']['height'],
          '#description' => t('Enter a height in pixels or as a percentage. i.e. 500 or 80%.'),
        );
        $form[$actionid]['data']['xoffset'] = array(
          '#type' => 'textfield',
          '#title' => t('X offset'),
          '#default_value' => $action['data']['xoffset'],
          '#description' => t('Enter an offset in pixels or use a keyword: <em>left</em>, <em>center</em>, or <em>right</em>.'),
        );
        $form[$actionid]['data']['yoffset'] = array(
          '#type' => 'textfield',
          '#title' => t('Y offset'),
          '#default_value' => $action['data']['yoffset'],
          '#description' => t('Enter an offset in pixels or use a keyword: <em>top</em>, <em>center</em>, or <em>bottom</em>.'),
        );
        break;
      case 'watermark':
    }
    $form[$actionid]['remove'] = array(
      '#type' => 'checkbox',
      '#title' => t('Remove this action'),
    );
  }
  $helptext = array();
  $helptext['scale'] = t('<strong>Scale</strong>: Resize an image maintaining the original aspect-ratio (only one value necessary).');
  $helptext['resize'] = t('<strong>Resize</strong>: Resize an image to an exact set of dimensions, ignoring aspect ratio.');
  $helptext['crop'] = t('<strong>Crop</strong>: Crop an image to the rectangle specified by the given offsets and dimensions.');
  $description = '<ul><li>' . implode('</li><li>', $helptext) . '</li><ul>';
  $form['newaction'] = array(
    '#type' => 'select',
    '#options' => array(
      '' => t('select...'),
      'scale' => t('Scale'),
      'resize' => t('Resize'),
      'crop' => t('Crop'),
    ),
    '#title' => t('Add a new action'),
    '#description' => $description,
  );
  return $form;
}

/**
 * Theme an img tag for displaying the image.
 */
function theme_imagecache_display($node, $label, $url, $attributes) {
  return '<img src="' . check_url($url) . '" alt="' . check_plain($node->title) . '" title="' . check_plain($node->title) . '" ' . drupal_attributes($attributes) . ' />';
}

/**
 * Verify the image module and toolkit settings.
 */
function _imagecache_check_settings() {

  // Sanity check : make sure we've got a working toolkit.
  if (!image_get_toolkit()) {
    drupal_set_message(t('Make sure you have a working image toolkit installed and enabled, for more information see: %settings.', array(
      '%settings' => l(t('Image toolkit settings'), 'admin/settings/image-toolkit'),
    )), 'error');
    return FALSE;
  }
  return TRUE;
}
function theme_imagecache_admin($form) {
  $output = '';
  $output .= '<p class="cvs-version">$Id$</p>';
  $output .= '<h2>' . drupal_render($form['title']) . '</h2>';
  $output .= drupal_render($form);
  return $output;
}
function theme_imagecache_formatter($field, $item, $formatter) {
  if (preg_match('/_linked$/', $formatter)) {
    $formatter = preg_replace('/_linked$/', '', $formatter);
    $image = theme('imagecache', $formatter, $item['filepath'], $item['alt'], $item['title']);
    $output = l($image, 'node/' . $item['nid'], array(), NULL, NULL, FALSE, TRUE);
  }
  else {
    $output = theme('imagecache', $formatter, $item['filepath'], $item['alt'], $item['title']);
  }
  return $output;
}
function theme_imagecache($namespace, $path, $alt = '', $title = '', $attributes = NULL) {
  $attributes = drupal_attributes($attributes);
  $imagecache_path = file_create_url(file_directory_path() . '/imagecache/' . $namespace . '/' . $path);
  return '<img src="' . $imagecache_path . '" alt="' . check_plain($alt) . '" title="' . check_plain($title) . '" ' . $attributes . ' />';
}

/**
 * Clear cached versions of a specific file in all presets.
 * @param $path
 *   The Drupal file path to the original image.
 */
function imagecache_image_flush($path) {
  $presets = _imagecache_get_presets();
  foreach ($presets as $presetid => $presetname) {
    $ipath = file_directory_path() . '/imagecache/' . $presetname . '/' . $path;
    file_delete($ipath);
  }
}

Functions

Namesort descending Description
imagecache_admin
imagecache_admin_submit
imagecache_admin_validate
imagecache_cache
imagecache_field_formatter Implementation of hook_field_formatter().
imagecache_field_formatter_info Implementation of hook_field_formatter_info().
imagecache_image_flush Clear cached versions of a specific file in all presets.
imagecache_menu Implementation of hook_menu().
imagecache_perm Implementation of hook_perm().
imagecache_requirements Implementation of hook_requirements().
theme_imagecache
theme_imagecache_admin
theme_imagecache_display Theme an img tag for displaying the image.
theme_imagecache_formatter
_imagecache_actions_form
_imagecache_actions_get_by_presetid
_imagecache_action_create
_imagecache_action_delete
_imagecache_action_update
_imagecache_check_settings Verify the image module and toolkit settings.
_imagecache_file_load
_imagecache_filter Filter key word values such as 'top', 'right', 'center', and also percentages. All returned values are in pixels relative to the passed in height and width.
_imagecache_get_presets
_imagecache_keyword_filter Accept a keyword (center, top, left, etc) and return it as an offset in pixels.
_imagecache_percent_filter Accept a percentage and return it in pixels.
_imagecache_preset_create Create a preset.
_imagecache_preset_delete
_imagecache_preset_flush Flush cached media for a preset.
_imagecache_preset_load Load a preset by id.
_imagecache_preset_load_by_name Load a preset by name.
_imagecache_preset_update Update a preset.
_imagecache_recursive_delete Recursively delete all files and folders in the specified filepath, then delete the containing folder.
_imagecache_strip_file_directory Remove a possible leading file directory path from the given path.