[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/imagecache/ -> imagecache.module (source)

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Dynamic image resizer and image cacher.
   6   *
   7   * ImageCache allows you to setup presets for image processing.
   8   * If an ImageCache derivative doesn't exist the web server's
   9   * rewrite rules will pass the request to Drupal which in turn
  10   * hands it off to imagecache to dynamically generate the file.
  11   *
  12   * To view a derivative image you request a special url containing
  13   * 'imagecache/<presetname>/path/to/file.ext.
  14   *
  15   * Presets can be managed at http://example.com/admin/build/imagecache.
  16   *
  17   * To view a derivative image you request a special url containing
  18   * 'imagecache/<presetname>/path/to/file.ext.
  19   *
  20   * If you had a preset names 'thumbnail' and you wanted to see the
  21   * thumbnail version of  http://example.com/files/path/to/myimage.jpg you
  22   * would use http://example.com/files/imagecache/thumbnail/path/to/myimage.jpg
  23   *
  24   * ImageCache provides formatters for CCK Imagefields and is leveraged by several
  25   * other modules. ImageCache also relies heavily on ImageAPI for it's image processing.
  26   * If there are errors with actual image processing look to ImageAPI first.
  27   *
  28   * @todo: add watermarking capabilities.
  29   *
  30   */
  31  
  32  /**
  33   * Imagecache preset storage constant for user-defined presets in the DB.
  34   */
  35  define('IMAGECACHE_STORAGE_NORMAL', 0);
  36  
  37  /**
  38   * Imagecache preset storage constant for module-defined presets in code.
  39   */
  40  define('IMAGECACHE_STORAGE_DEFAULT', 1);
  41  
  42  /**
  43   * Imagecache preset storage constant for user-defined presets that override
  44   * module-defined presets.
  45   */
  46  define('IMAGECACHE_STORAGE_OVERRIDE', 2);
  47  
  48  /*********************************************************************************************
  49   * Drupal Hooks
  50   *********************************************************************************************/
  51  
  52  /**
  53   * Implementation of hook_perm().
  54   */
  55  function imagecache_perm() {
  56    $perms =  array('administer imagecache', 'flush imagecache');
  57    foreach (imagecache_presets() as $preset) {
  58      $perms[] =  'view imagecache '. $preset['presetname'];
  59    }
  60    return $perms;
  61  }
  62  
  63  /**
  64   * Implementation of hook_menu().
  65   */
  66  function imagecache_menu() {
  67    $items = array();
  68  
  69    // standard imagecache callback.
  70    $items[file_directory_path() .'/imagecache'] = array(
  71      'page callback' => 'imagecache_cache',
  72      'access callback' => '_imagecache_menu_access_public_files',
  73      'type' => MENU_CALLBACK
  74    );
  75    // private downloads imagecache callback
  76    $items['system/files/imagecache'] = array(
  77      'page callback' => 'imagecache_cache_private',
  78      'access callback' => TRUE,
  79      'type' => MENU_CALLBACK
  80    );
  81  
  82    return $items;
  83  }
  84  
  85  /**
  86   * Menu access callback for public file transfers.
  87   */
  88  function _imagecache_menu_access_public_files() {
  89    return (FILE_DOWNLOADS_PUBLIC == variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC));
  90  }
  91  
  92  /**
  93   * Implementation of hook_form_FORM_ID_alter.
  94   *
  95   * Clear imagecache presets cache on admin/build/modules form.
  96   */
  97  function imagecache_form_system_modules_alter(&$form, $form_state) {
  98    imagecache_presets(TRUE);
  99  }
 100  
 101  /**
 102   * Implementation of hook_form_FORM_ID_alter.
 103   *
 104   * The file system form is modified to include an extra submit handler, so
 105   * that imagecache can rebuild the menu after the filesystem path is changed.
 106   */
 107  function imagecache_form_system_file_system_settings_alter(&$form, &$form_state) {
 108    $form['#submit'][] = 'imagecache_system_file_system_submit';
 109  }
 110  
 111  /**
 112   * Rebuild menus to ensure we've got the right files directory callback.
 113   */
 114  function imagecache_system_file_system_submit($form, &$form_state) {
 115    menu_rebuild();
 116  }
 117  
 118  
 119  /**
 120   * Implementation of hook_theme().
 121   */
 122  function imagecache_theme() {
 123    $theme = array(
 124      'imagecache' => array(
 125        'arguments' => array(
 126          'namespace' => NULL,
 127          'path' => NULL,
 128          'alt' => NULL,
 129          'title' => NULL,
 130      )),
 131      'imagecache_imagelink' => array(
 132        'arguments' => array(
 133          'namespace' => NULL,
 134          'path' => NULL,
 135          'alt' => NULL,
 136          'title' => NULL,
 137          'attributes' => array(),
 138      )),
 139      'imagecache_resize' => array(
 140        'file' => 'imagecache_actions.inc',
 141        'arguments' => array('element' => NULL),
 142      ),
 143      'imagecache_scale' => array(
 144        'file' => 'imagecache_actions.inc',
 145        'arguments' => array('element' => NULL),
 146      ),
 147      'imagecache_scale_and_crop' => array(
 148        'file' => 'imagecache_actions.inc',
 149        'arguments' => array('element' => NULL),
 150      ),
 151      'imagecache_deprecated_scale' => array(
 152        'file' => 'imagecache_actions.inc',
 153        'arguments' => array('element' => NULL),
 154      ),
 155      'imagecache_crop' => array(
 156        'file' => 'imagecache_actions.inc',
 157        'arguments' => array('element' => NULL),
 158      ),
 159      'imagecache_desaturate' => array(
 160        'file' => 'imagecache_actions.inc',
 161        'arguments' => array('element' => NULL),
 162      ),
 163      'imagecache_rotate' => array(
 164        'file' => 'imagecache_actions.inc',
 165        'arguments' => array('element' => NULL),
 166      ),
 167      'imagecache_sharpen' => array(
 168        'file' => 'imagecache_actions.inc',
 169        'arguments' => array('element' => NULL),
 170      ),
 171    );
 172  
 173    foreach (imagecache_presets() as $preset) {
 174      $theme['imagecache_formatter_'. $preset['presetname'] .'_default'] = array(
 175        'arguments' => array('element' => NULL),
 176        'function' => 'theme_imagecache_formatter_default',
 177      );
 178      $theme['imagecache_formatter_'. $preset['presetname'] .'_linked'] = array(
 179        'arguments' => array('element' => NULL),
 180        'function' => 'theme_imagecache_formatter_linked',
 181      );
 182      $theme['imagecache_formatter_'. $preset['presetname'] .'_imagelink'] = array(
 183        'arguments' => array('element' => NULL),
 184        'function' => 'theme_imagecache_formatter_imagelink',
 185      );
 186      $theme['imagecache_formatter_'. $preset['presetname'] .'_path'] = array(
 187        'arguments' => array('element' => NULL),
 188        'function' => 'theme_imagecache_formatter_path',
 189      );
 190      $theme['imagecache_formatter_'. $preset['presetname'] .'_url'] = array(
 191        'arguments' => array('element' => NULL),
 192        'function' => 'theme_imagecache_formatter_url',
 193      );
 194    }
 195  
 196    return $theme;
 197  
 198  }
 199  
 200  /**
 201   * Implementation of hook_imagecache_actions.
 202   *
 203   * @return array
 204   *   An array of information on the actions implemented by a module. The array
 205   *   contains a sub-array for each action node type, with the machine-readable
 206   *   action name as the key. Each sub-array has up to 3 attributes. Possible
 207   *   attributes:
 208   *
 209   *     "name": the human-readable name of the action. Required.
 210   *     "description": a brief description of the action. Required.
 211   *     "file": the name of the include file the action can be found
 212   *             in relative to the implementing module's path.
 213   */
 214  function imagecache_imagecache_actions() {
 215    $actions = array(
 216      'imagecache_resize' => array(
 217        'name' => 'Resize',
 218        'description' => 'Resize an image to an exact set of dimensions, ignoring aspect ratio.',
 219        'file' => 'imagecache_actions.inc',
 220      ),
 221      'imagecache_scale' => array(
 222        'name' => 'Scale',
 223        'description' => 'Resize an image maintaining the original aspect-ratio (only one value necessary).',
 224        'file' => 'imagecache_actions.inc',
 225      ),
 226      'imagecache_deprecated_scale' => array(
 227        'name' => 'Deprecated Scale',
 228        'description' => 'Precursor to Scale and Crop. Has inside and outside dimension support. This action will be removed in ImageCache 2.1).',
 229        'file' => 'imagecache_actions.inc',
 230      ),
 231      'imagecache_scale_and_crop' => array(
 232        'name' => 'Scale And Crop',
 233        'description' => 'Resize an image while maintaining aspect ratio, then crop it to the specified dimensions.',
 234        'file' => 'imagecache_actions.inc',
 235      ),
 236      'imagecache_crop' => array(
 237        'name' => 'Crop',
 238        'description' => 'Crop an image to the rectangle specified by the given offsets and dimensions.',
 239        'file' => 'imagecache_actions.inc',
 240      ),
 241      'imagecache_desaturate' => array(
 242        'name' => 'Desaturate',
 243        'description' => 'Convert an image to grey scale.',
 244        'file' => 'imagecache_actions.inc',
 245      ),
 246      'imagecache_rotate' => array(
 247        'name' => 'Rotate',
 248        'description' => 'Rotate an image.',
 249        'file' => 'imagecache_actions.inc',
 250      ),
 251      'imagecache_sharpen' => array(
 252        'name' => 'Sharpen',
 253        'description' => 'Sharpen an image using unsharp masking.',
 254        'file' => 'imagecache_actions.inc',
 255      ),
 256    );
 257  
 258    return $actions;
 259  }
 260  
 261  /**
 262   * Pull in actions exposed by other modules using hook_imagecache_actions().
 263   *
 264   * @param $reset
 265   *   Boolean flag indicating whether the cached data should be
 266   *   wiped and recalculated.
 267   *
 268   * @return
 269   *   An array of actions to be used when transforming images.
 270   */
 271  function imagecache_action_definitions($reset = FALSE) {
 272    static $actions;
 273    if (!isset($actions) || $reset) {
 274      if (!$reset && ($cache = cache_get('imagecache_actions')) && !empty($cache->data)) {
 275        $actions = $cache->data;
 276      }
 277      else {
 278        foreach (module_implements('imagecache_actions') as $module) {
 279          foreach (module_invoke($module, 'imagecache_actions') as $key => $action) {
 280            $action['module'] = $module;
 281            if (!empty($action['file'])) {
 282              $action['file'] = drupal_get_path('module', $action['module']) .'/'. $action['file'];
 283            }
 284            $actions[$key] = $action;
 285          };
 286        }
 287        uasort($actions, '_imagecache_definitions_sort');
 288        cache_set('imagecache_actions', $actions);
 289      }
 290    }
 291    return $actions;
 292  }
 293  
 294  function _imagecache_definitions_sort($a, $b) {
 295    $a = $a['name'];
 296    $b = $b['name'];
 297    if ($a == $b) {
 298      return 0;
 299    }
 300    return ($a < $b) ? -1 : 1;
 301  }
 302  
 303  function imagecache_action_definition($action) {
 304    static $definition_cache;
 305    if (!isset($definition_cache[$action])) {
 306      $definitions = imagecache_action_definitions();
 307      $definition = (isset($definitions[$action])) ? $definitions[$action] : array();
 308  
 309      if (isset($definition['file'])) {
 310        require_once($definition['file']);
 311      }
 312      $definition_cache[$action] = $definition;
 313    }
 314    return $definition_cache[$action];
 315  }
 316  
 317  /**
 318   * Return a URL that points to the location of a derivative of the original
 319   * image transformed with the given preset.
 320   *
 321   * Special care is taken to make this work with the possible combinations of
 322   * Clean URLs and public/private downloads. For example, when Clean URLs are not
 323   * available an URL with query should be returned, like
 324   * http://example.com/?q=files/imagecache/foo.jpg, so that ImageCache is able
 325   * intercept the request for this file.
 326   *
 327   * This code began similarly to Drupal core's function file_create_url(), but
 328   * handles the case of Clean URLs and public downloads differently however.
 329   * It also implements hook_file_url_alter() which was added to Drupal 7 and
 330   * backported to PressFlow 6.x.
 331   *
 332   * @param $presetname
 333   *   String specifying an ImageCache preset name.
 334   * @param $filepath
 335   *   String specifying the path to the image file.
 336   * @param $bypass_browser_cache
 337   *   A Boolean indicating that the URL for the image should be distinct so that
 338   *   the visitors browser will not be able to use a previously cached version.
 339   *   Defaults to FALSE.
 340   * @param $absolute
 341   *   A Boolean indicating that the URL should be absolute. Defaults to TRUE.
 342   */
 343  function imagecache_create_url($presetname, $filepath, $bypass_browser_cache = FALSE, $absolute = TRUE) {
 344    $args = array('query' => empty($bypass_browser_cache) ? NULL : time());
 345    $file_directory = file_directory_path();
 346  
 347    // Determine the path of the derivative inside the files directory.
 348    $derivative_path = 'imagecache/'. $presetname .'/'. _imagecache_strip_file_directory($filepath);
 349  
 350    // Then construct a full path and see if anyone wants to alter it.
 351    $altered_path = $old_path = $file_directory .'/'. $derivative_path;
 352    drupal_alter('file_url', $altered_path);
 353  
 354    // If any module has altered the path, then return the alteration...
 355    if ($altered_path != $old_path) {
 356      // ...but use url() so our $bypass_browser_cache parameter is honored.
 357      return url($altered_path, $args);
 358    }
 359  
 360    // It was unchanged so use the download method's prefix.
 361    $prefix = array(
 362      FILE_DOWNLOADS_PUBLIC => $file_directory,
 363      FILE_DOWNLOADS_PRIVATE => 'system/files',
 364    );
 365    $path = $prefix[variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)] .'/'. $derivative_path;
 366  
 367    return url($path, $args + array('absolute' => $absolute));
 368  }
 369  
 370  /**
 371   * Return a file system location that points to the location of a derivative
 372   * of the original image at @p $path, transformed with the given @p $preset.
 373   * Keep in mind that the image might not yet exist and won't be created.
 374   */
 375  function imagecache_create_path($presetname, $path) {
 376    $path = _imagecache_strip_file_directory($path);
 377    return file_create_path() .'/imagecache/'. $presetname .'/'. $path;
 378  }
 379  
 380  /**
 381   * Remove a possible leading file directory path from the given path.
 382   */
 383  function _imagecache_strip_file_directory($path) {
 384    $dirpath = file_directory_path();
 385    $dirlen = strlen($dirpath);
 386    if (substr($path, 0, $dirlen + 1) == $dirpath .'/') {
 387      $path = substr($path, $dirlen + 1);
 388    }
 389    return $path;
 390  }
 391  
 392  
 393  /**
 394   * callback for handling public files imagecache requests.
 395   */
 396  function imagecache_cache() {
 397    $args = func_get_args();
 398    $preset = check_plain(array_shift($args));
 399    $path = implode('/', $args);
 400    _imagecache_cache($preset, $path);
 401  }
 402  
 403  /**
 404   * callback for handling private files imagecache requests
 405   */
 406  function imagecache_cache_private() {
 407    $args = func_get_args();
 408    $preset = check_plain(array_shift($args));
 409    $source = implode('/', $args);
 410  
 411    if (user_access('view imagecache '. $preset) && !in_array(-1, module_invoke_all('file_download', $source))) {
 412      _imagecache_cache($preset, $source);
 413    }
 414    else {
 415      // if there is a 403 image, display it.
 416      $accesspath = file_create_path('imagecache/'. $preset .'.403.png');
 417      if (is_file($accesspath)) {
 418        imagecache_transfer($accesspath);
 419        exit;
 420      }
 421      header('HTTP/1.0 403 Forbidden');
 422      exit;
 423    }
 424  }
 425  
 426  /**
 427   * Handle request validation and responses to ImageCache requests.
 428   *
 429   * @see imagecache_generate_image() if you're writing code that needs to have
 430   *   ImageCache generate images but not send them to a browser.
 431   */
 432  function _imagecache_cache($presetname, $path) {
 433    if (!$preset = imagecache_preset_by_name($presetname)) {
 434      // Send a 404 if we don't know of a preset.
 435      header("HTTP/1.0 404 Not Found");
 436      exit;
 437    }
 438  
 439    // umm yeah deliver it early if it is there. especially useful
 440    // to prevent lock files from being created when delivering private files.
 441    $dst = imagecache_create_path($preset['presetname'], $path);
 442    if (is_file($dst)) {
 443      imagecache_transfer($dst);
 444    }
 445  
 446    // preserve path for watchdog.
 447    $src = $path;
 448  
 449    // Check if the path to the file exists.
 450    if (!is_file($src) && !is_file($src = file_create_path($src))) {
 451      watchdog('imagecache', '404: Unable to find %image ', array('%image' => $src), WATCHDOG_ERROR);
 452      header("HTTP/1.0 404 Not Found");
 453      exit;
 454    };
 455  
 456    // Bail if the requested file isn't an image you can't request .php files
 457    // etc...
 458    if (!getimagesize($src)) {
 459      watchdog('imagecache', '403: File is not an image %image ', array('%image' => $src), WATCHDOG_ERROR);
 460      header('HTTP/1.0 403 Forbidden');
 461      exit;
 462    }
 463  
 464    $lockfile = file_directory_temp() .'/'. $preset['presetname'] . basename($src);
 465    if (file_exists($lockfile)) {
 466      watchdog('imagecache', 'ImageCache already generating: %dst, Lock file: %tmp.', array('%dst' => $dst, '%tmp' => $lockfile), WATCHDOG_NOTICE);
 467      // 307 Temporary Redirect, to myself. Lets hope the image is done next time around.
 468      header('Location: '. request_uri(), TRUE, 307);
 469      exit;
 470    }
 471    touch($lockfile);
 472    // register the shtdown function to clean up lock files. by the time shutdown
 473    // functions are being called the cwd has changed from document root, to
 474    // server root so absolute paths must be used for files in shutdown functions.
 475    register_shutdown_function('file_delete', realpath($lockfile));
 476  
 477    // check if deriv exists... (file was created between apaches request handler and reaching this code)
 478    // otherwise try to create the derivative.
 479    if (file_exists($dst) || imagecache_build_derivative($preset['actions'], $src, $dst)) {
 480      imagecache_transfer($dst);
 481    }
 482    // Generate an error if image could not generate.
 483    watchdog('imagecache', 'Failed generating an image from %image using imagecache preset %preset.', array('%image' => $path, '%preset' => $preset['presetname']), WATCHDOG_ERROR);
 484    header("HTTP/1.0 500 Internal Server Error");
 485    exit;
 486  }
 487  
 488  /**
 489   * Apply an action to an image.
 490   *
 491   * @param $action
 492   *   Action array
 493   * @param $image
 494   *   Image object
 495   * @return
 496   *   Boolean, TRUE indicating success and FALSE failure.
 497   */
 498  function _imagecache_apply_action($action, &$image) {
 499    $actions = imagecache_action_definitions();
 500  
 501    if ($definition = imagecache_action_definition($action['action'])) {
 502      $function = $action['action'] .'_image';
 503      if (function_exists($function)) {
 504        return $function($image, $action['data']);
 505      }
 506    }
 507    // skip undefined actions.. module probably got uninstalled or disabled.
 508    watchdog('imagecache', 'non-existant action %action', array('%action' => $action['action']), WATCHDOG_NOTICE);
 509    return TRUE;
 510  }
 511  
 512  /**
 513   * Helper function to transfer files from imagecache.
 514   *
 515   * Determines MIME type and sets a last modified header.
 516   *
 517   * @param $path
 518   *   String containing the path to file to be transferred.
 519   * @return
 520   *   This function does not return. It calls exit().
 521   */
 522  
 523  function imagecache_transfer($path) {
 524    $size = getimagesize($path);
 525    $headers = array('Content-Type: '. mime_header_encode($size['mime']));
 526  
 527    if ($fileinfo = stat($path)) {
 528      $headers[] = 'Content-Length: '. $fileinfo[7];
 529      $headers[] = 'Expires: ' . gmdate('D, d M Y H:i:s', time() + 1209600) .' GMT';
 530      $headers[] = 'Cache-Control: max-age=1209600, private, must-revalidate';
 531      _imagecache_cache_set_cache_headers($fileinfo, $headers);
 532    }
 533    file_transfer($path, $headers);
 534    exit;
 535  }
 536  
 537  /**
 538   * Set file headers that handle "If-Modified-Since" correctly for the
 539   * given fileinfo.
 540   *
 541   * Note that this function may return or may call exit().
 542   *
 543   * Most code has been taken from drupal_page_cache_header().
 544   *
 545   * @param $fileinfo
 546   *   Array returned by stat().
 547   * @param
 548   *   Array of existing headers.
 549   * @return
 550   *   Nothing but beware that this function may not return.
 551   */
 552  function _imagecache_cache_set_cache_headers($fileinfo, &$headers) {
 553    // Set default values:
 554    $last_modified = gmdate('D, d M Y H:i:s', $fileinfo[9]) .' GMT';
 555    $etag = '"'. md5($last_modified) .'"';
 556  
 557    // See if the client has provided the required HTTP headers:
 558    $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
 559                          ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE'])
 560                          : FALSE;
 561    $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH'])
 562                      ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
 563                      : FALSE;
 564  
 565    if ($if_modified_since && $if_none_match
 566        && $if_none_match == $etag // etag must match
 567        && $if_modified_since == $last_modified) { // if-modified-since must match
 568      header('HTTP/1.1 304 Not Modified');
 569      // All 304 responses must send an etag if the 200 response
 570      // for the same object contained an etag
 571      header('Etag: '. $etag);
 572      // We must also set Last-Modified again, so that we overwrite Drupal's
 573      // default Last-Modified header with the right one
 574      header('Last-Modified: '. $last_modified);
 575      exit;
 576    }
 577  
 578    // Send appropriate response:
 579    $headers[] = 'Last-Modified: '. $last_modified;
 580    $headers[] = 'ETag: '. $etag;
 581  }
 582  
 583  /**
 584   * Create a new image based on an image preset.
 585   *
 586   * @param $preset
 587   *   An image preset array.
 588   * @param $source
 589   *   Path of the source file.
 590   * @param $destination
 591   *   Path of the destination file.
 592   * @return
 593   *   TRUE if an image derivative is generated, FALSE if no image
 594   *  derivative is generated. NULL if the derivative is being generated.
 595   */
 596  function imagecache_build_derivative($actions, $src, $dst) {
 597    // get the folder for the final location of this preset...
 598    $dir = dirname($dst);
 599  
 600    // Build the destination folder tree if it doesn't already exists.
 601    if (!file_check_directory($dir, FILE_CREATE_DIRECTORY) && !mkdir($dir, 0775, TRUE)) {
 602      watchdog('imagecache', 'Failed to create imagecache directory: %dir', array('%dir' => $dir), WATCHDOG_ERROR);
 603      return FALSE;
 604    }
 605  
 606    // file_check_directory() has an annoying habit of displaying "directory ...
 607    // has been created" status messages. To avoid confusing visitors we clear
 608    // out all the status messages for non-ImageCache admins. This might affect
 609    // some other messages but errors and warnings should still be displayed.
 610    if (!user_access('administer imagecache')) {
 611      drupal_get_messages('status', TRUE);
 612    }
 613  
 614    // Simply copy the file if there are no actions.
 615    if (empty($actions)) {
 616      return file_copy($src, $dst, FILE_EXISTS_REPLACE);
 617    }
 618  
 619    if (!$image = imageapi_image_open($src)) {
 620      return FALSE;
 621    }
 622  
 623    if (file_exists($dst)) {
 624      watchdog('imagecache', 'Cached image file %dst already exists but is being regenerated. There may be an issue with your rewrite configuration.', array('%dst' => $dst), WATCHDOG_WARNING);
 625    }
 626  
 627    foreach ($actions as $action) {
 628      if (!empty($action['data'])) {
 629        // Make sure the width and height are computed first so they can be used
 630        // in relative x/yoffsets like 'center' or 'bottom'.
 631        if (isset($action['data']['width'])) {
 632          $action['data']['width']   = _imagecache_percent_filter($action['data']['width'], $image->info['width']);
 633        }
 634        if (isset($action['data']['height'])) {
 635          $action['data']['height']  = _imagecache_percent_filter($action['data']['height'], $image->info['height']);
 636        }
 637        if (isset($action['data']['xoffset'])) {
 638          $action['data']['xoffset'] = _imagecache_keyword_filter($action['data']['xoffset'], $image->info['width'], $action['data']['width']);
 639        }
 640        if (isset($action['data']['yoffset'])) {
 641          $action['data']['yoffset'] = _imagecache_keyword_filter($action['data']['yoffset'], $image->info['height'], $action['data']['height']);
 642        }
 643      }
 644      if (!_imagecache_apply_action($action, $image)) {
 645        watchdog('imagecache', 'action(id:%id): %action failed for %src', array('%id' => $action['actionid'], '%action' => $action['action'], '%src' => $src), WATCHDOG_ERROR);
 646        return FALSE;
 647      }
 648    }
 649  
 650    if (!imageapi_image_close($image, $dst)) {
 651      watchdog('imagecache', 'There was an error saving the new image file %dst.', array('%dst' => $dst), WATCHDOG_ERROR);
 652      return FALSE;
 653    }
 654  
 655    return TRUE;
 656  }
 657  
 658  /**
 659   * Implementation of hook_user().
 660   */
 661  function imagecache_user($op, &$edit, &$account, $category = NULL) {
 662    // Flush cached old user picture.
 663    if ($op == 'update' && !empty($account->picture)) {
 664      imagecache_image_flush($account->picture);
 665    }
 666  }
 667  
 668  /**
 669   * Implementation of filefield.module's hook_file_delete().
 670   *
 671   * Remove derivative images after the originals are deleted by filefield.
 672   */
 673  function imagecache_file_delete($file) {
 674    imagecache_image_flush($file->filepath);
 675  }
 676  
 677  /**
 678   * Implementation of hook_field_formatter_info().
 679   *
 680   * imagecache formatters are named as $presetname_$style
 681   * $style is used to determine how the preset should be rendered.
 682   * If you are implementing custom imagecache formatters please treat _ as
 683   * reserved.
 684   *
 685   * @todo: move the linking functionality up to imagefield and clean up the default image
 686   * integration.
 687   */
 688  function imagecache_field_formatter_info() {
 689    $formatters = array();
 690    foreach (imagecache_presets() as $preset) {
 691      $formatters[$preset['presetname'] .'_default'] = array(
 692        'label' => t('@preset image', array('@preset' => $preset['presetname'])),
 693        'field types' => array('image', 'filefield'),
 694      );
 695      $formatters[$preset['presetname'] .'_linked'] = array(
 696        'label' => t('@preset image linked to node', array('@preset' => $preset['presetname'])),
 697        'field types' => array('image', 'filefield'),
 698      );
 699      $formatters[$preset['presetname'] .'_imagelink'] = array(
 700        'label' => t('@preset image linked to image', array('@preset' => $preset['presetname'])),
 701        'field types' => array('image', 'filefield'),
 702      );
 703      $formatters[$preset['presetname'] .'_path'] = array(
 704        'label' => t('@preset file path', array('@preset' => $preset['presetname'])),
 705        'field types' => array('image', 'filefield'),
 706      );
 707      $formatters[$preset['presetname'] .'_url'] = array(
 708        'label' => t('@preset URL', array('@preset' => $preset['presetname'])),
 709        'field types' => array('image', 'filefield'),
 710      );
 711    }
 712    return $formatters;
 713  }
 714  
 715  function theme_imagecache_formatter_default($element) {
 716    // Inside a view $element may contain NULL data. In that case, just return.
 717    if (empty($element['#item']['fid'])) {
 718      return '';
 719    }
 720  
 721    // Extract the preset name from the formatter name.
 722    $presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
 723    $style = 'linked';
 724    $style = 'default';
 725  
 726    $item = $element['#item'];
 727    $item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
 728    $item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
 729  
 730    $class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
 731    return theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title'], array('class' => $class));
 732  }
 733  
 734  function theme_imagecache_formatter_linked($element) {
 735    // Inside a view $element may contain NULL data. In that case, just return.
 736    if (empty($element['#item']['fid'])) {
 737      return '';
 738    }
 739  
 740    // Extract the preset name from the formatter name.
 741    $presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
 742    $style = 'linked';
 743  
 744    $item = $element['#item'];
 745    $item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
 746    $item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
 747  
 748    $imagetag = theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title']);
 749    $path = empty($item['nid']) ? '' : 'node/'. $item['nid'];
 750    $class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
 751    return l($imagetag, $path, array('attributes' => array('class' => $class), 'html' => TRUE));
 752  }
 753  
 754  function theme_imagecache_formatter_imagelink($element) {
 755    // Inside a view $element may contain NULL data. In that case, just return.
 756    if (empty($element['#item']['fid'])) {
 757      return '';
 758    }
 759  
 760    // Extract the preset name from the formatter name.
 761    $presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
 762    $style = 'imagelink';
 763  
 764    $item = $element['#item'];
 765    $item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
 766    $item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
 767  
 768    $imagetag = theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title']);
 769    $path = file_create_url($item['filepath']);
 770    $class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
 771    return l($imagetag, $path, array('attributes' => array('class' => $class), 'html' => TRUE));
 772  }
 773  
 774  function theme_imagecache_formatter_path($element) {
 775    // Inside a view $element may contain NULL data. In that case, just return.
 776    if (empty($element['#item']['fid'])) {
 777      return '';
 778    }
 779  
 780    // Extract the preset name from the formatter name.
 781    $presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
 782  
 783    return imagecache_create_path($presetname, $element['#item']['filepath']);
 784  }
 785  
 786  function theme_imagecache_formatter_url($element) {
 787    // Inside a view $element may contain NULL data. In that case, just return.
 788    if (empty($element['#item']['fid'])) {
 789      return '';
 790    }
 791  
 792    // Extract the preset name from the formatter name.
 793    $presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
 794  
 795    return imagecache_create_url($presetname, $element['#item']['filepath']);
 796  }
 797  
 798  /**
 799   * Accept a percentage and return it in pixels.
 800   */
 801  function _imagecache_percent_filter($value, $current_pixels) {
 802    if (strpos($value, '%') !== FALSE) {
 803      $value = str_replace('%', '', $value) * 0.01 * $current_pixels;
 804    }
 805    return $value;
 806  }
 807  
 808  /**
 809   * Accept a keyword (center, top, left, etc) and return it as an offset in pixels.
 810   */
 811  function _imagecache_keyword_filter($value, $current_pixels, $new_pixels) {
 812    switch ($value) {
 813      case 'top':
 814      case 'left':
 815        $value = 0;
 816        break;
 817      case 'bottom':
 818      case 'right':
 819        $value = $current_pixels - $new_pixels;
 820        break;
 821      case 'center':
 822        $value = $current_pixels/2 - $new_pixels/2;
 823        break;
 824    }
 825    return $value;
 826  }
 827  
 828  /**
 829   * Recursively delete all files and folders in the specified filepath, then
 830   * delete the containing folder.
 831   *
 832   * Note that this only deletes visible files with write permission.
 833   *
 834   * @param string $path
 835   *   A filepath relative to file_directory_path.
 836   */
 837  function _imagecache_recursive_delete($path) {
 838    if (is_file($path) || is_link($path)) {
 839      unlink($path);
 840    }
 841    elseif (is_dir($path)) {
 842      $d = dir($path);
 843      while (($entry = $d->read()) !== FALSE) {
 844        if ($entry == '.' || $entry == '..') continue;
 845        $entry_path = $path .'/'. $entry;
 846        _imagecache_recursive_delete($entry_path);
 847      }
 848      $d->close();
 849      rmdir($path);
 850    }
 851    else {
 852      watchdog('imagecache', 'Unknown file type(%path) stat: %stat ',
 853                array('%path' => $path,  '%stat' => print_r(stat($path),1)), WATCHDOG_ERROR);
 854    }
 855  
 856  }
 857  
 858  /**
 859   * Create and image tag for an imagecache derivative
 860   *
 861   * @param $presetname
 862   *   String with the name of the preset used to generate the derivative image.
 863   * @param $path
 864   *   String path to the original image you wish to create a derivative image
 865   *   tag for.
 866   * @param $alt
 867   *   Optional string with alternate text for the img element.
 868   * @param $title
 869   *   Optional string with title for the img element.
 870   * @param $attributes
 871   *   Optional drupal_attributes() array. If $attributes is an array then the
 872   *   default imagecache classes will not be set automatically, you must do this
 873   *   manually.
 874   * @param $getsize
 875   *   If set to TRUE, the image's dimension are fetched and added as width/height
 876   *   attributes.
 877   * @param $absolute
 878   *   A Boolean indicating that the URL should be absolute. Defaults to TRUE.
 879   * @return
 880   *   HTML img element string.
 881   */
 882  function theme_imagecache($presetname, $path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE, $absolute = TRUE) {
 883    // Check is_null() so people can intentionally pass an empty array of
 884    // to override the defaults completely.
 885    if (is_null($attributes)) {
 886      $attributes = array('class' => 'imagecache imagecache-'. $presetname);
 887    }
 888    if ($getsize && ($image = image_get_info(imagecache_create_path($presetname, $path)))) {
 889      $attributes['width'] = $image['width'];
 890      $attributes['height'] = $image['height'];
 891    }
 892  
 893    $attributes = drupal_attributes($attributes);
 894    $imagecache_url = imagecache_create_url($presetname, $path, FALSE, $absolute);
 895    return '<img src="'. $imagecache_url .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. $attributes .' />';
 896  }
 897  
 898  /**
 899   * Create a link the original image that wraps the derivative image.
 900   *
 901   * @param $presetname
 902   *   String with the name of the preset used to generate the derivative image.
 903   * @param $path
 904   *   String path to the original image you wish to create a derivative image
 905   *   tag for.
 906   * @param $alt
 907   *   Optional string with alternate text for the img element.
 908   * @param $title
 909   *   Optional string with title for the img element.
 910   * @param attributes
 911   *   Optional drupal_attributes() array for the link.
 912   * @return
 913   *   An HTML string.
 914   */
 915  function theme_imagecache_imagelink($presetname, $path, $alt = '', $title = '', $attributes = NULL) {
 916    $image = theme('imagecache', $presetname, $path, $alt, $title);
 917    $original_image_url = file_create_url($path);
 918    return l($image, $original_image_url, array('absolute' => FALSE, 'html' => TRUE, 'attributes' => $attributes));
 919  }
 920  
 921  /**
 922   * Imagecache JS settings and theme function.
 923   */
 924  function imagecache_add_js() {
 925    static $added;
 926    if (!$added) {
 927      $added = TRUE;
 928      drupal_add_js(drupal_get_path('module', 'imagecache') .'/imagecache.js');
 929  
 930      $mode = variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC);
 931      if ($mode == FILE_DOWNLOADS_PUBLIC) {
 932        $settings['filesUrl'] = $GLOBALS['base_path'] . file_directory_path();
 933      }
 934      elseif ($mode == FILE_DOWNLOADS_PRIVATE) {
 935        $settings['filesUrl'] = 'system/files';
 936      }
 937      $settings['filesDirectory'] = file_directory_path();
 938      $settings['presets'] = array_keys(imagecache_presets());
 939      drupal_add_js(array('imagecache' => $settings), 'setting');
 940    }
 941  }
 942  
 943  /**
 944   *  ImageCache 2.x API
 945   *
 946   *  The API for imagecache has changed.  The 2.x API returns more structured
 947   *  data, has shorter function names, and implements more aggressive metadata
 948   *  caching.
 949   *
 950   */
 951  
 952  /**
 953   * Get an array of all presets and their settings.
 954   *
 955   * @param reset
 956   *   if set to TRUE it will clear the preset cache
 957   *
 958   * @return
 959   *   array of presets array( $preset_id => array('presetid' => integer, 'presetname' => string))
 960   */
 961  function imagecache_presets($reset = FALSE) {
 962    static $presets = array();
 963  
 964    // Clear  caches if $reset is TRUE;
 965    if ($reset) {
 966      $presets = array();
 967      cache_clear_all('imagecache:presets', 'cache');
 968  
 969      // Clear the content.module cache (refreshes the list of formatters provided by imagefield.module).
 970      if (module_exists('content')) {
 971        content_clear_type_cache();
 972      }
 973    }
 974    // Return presets if the array is populated.
 975    if (!empty($presets)) {
 976      return $presets;
 977    }
 978  
 979    // Grab from cache or build the array. To ensure that the Drupal 5 upgrade
 980    // path works, we also check whether the presets list is an array.
 981    if (($cache = cache_get('imagecache:presets', 'cache')) && is_array($cache->data)) {
 982      $presets = $cache->data;
 983    }
 984    else {
 985      $normal_presets = array();
 986  
 987      $result = db_query('SELECT * FROM {imagecache_preset} ORDER BY presetname');
 988      while ($preset = db_fetch_array($result)) {
 989        $presets[$preset['presetid']] = $preset;
 990        $presets[$preset['presetid']]['actions'] = imagecache_preset_actions($preset);
 991        $presets[$preset['presetid']]['storage'] = IMAGECACHE_STORAGE_NORMAL;
 992  
 993        // Collect normal preset names so we can skip defaults and mark overrides accordingly
 994        $normal_presets[$preset['presetname']] = $preset['presetid'];
 995      }
 996  
 997      // Collect default presets and allow modules to modify them before they
 998      // are cached.
 999      $default_presets = module_invoke_all('imagecache_default_presets');
1000      drupal_alter('imagecache_default_presets', $default_presets);
1001  
1002      // Add in default presets if they don't conflict with any normal presets.
1003      // Mark normal presets that take the same preset namespace as overrides.
1004      foreach ($default_presets as $preset) {
1005        if (!empty($preset['presetname'])) {
1006          if (!isset($normal_presets[$preset['presetname']])) {
1007            $preset['storage'] = IMAGECACHE_STORAGE_DEFAULT;
1008            // Use a string preset identifier
1009            $preset['presetid'] = $preset['presetname'];
1010            $presets[$preset['presetname']] = $preset;
1011          }
1012          else {
1013            $presetid = $normal_presets[$preset['presetname']];
1014            $presets[$presetid]['storage'] = IMAGECACHE_STORAGE_OVERRIDE;
1015          }
1016        }
1017      }
1018  
1019      cache_set('imagecache:presets', $presets);
1020    }
1021    return $presets;
1022  }
1023  
1024  /**
1025   * Load a preset by preset_id.
1026   *
1027   * @param preset_id
1028   *   The numeric id of a preset.
1029   *
1030   * @return
1031   *   preset array( 'presetname' => string, 'presetid' => integet)
1032   *   empty array if preset_id is an invalid preset
1033   */
1034  function imagecache_preset($preset_id, $reset = FALSE) {
1035    $presets = imagecache_presets($reset);
1036    return (isset($presets[$preset_id])) ? $presets[$preset_id] : array();
1037  }
1038  
1039  /**
1040   * Load a preset by name.
1041   *
1042   * @param preset_name
1043   *
1044   * @return
1045   *   preset array( 'presetname' => string, 'presetid' => integer)
1046   *   empty array if preset_name is an invalid preset
1047   */
1048  
1049  function imagecache_preset_by_name($preset_name) {
1050    static $presets_by_name = array();
1051    if (!$presets_by_name &&  $presets = imagecache_presets()) {
1052      foreach ($presets as $preset) {
1053        $presets_by_name[$preset['presetname']] = $preset;
1054      }
1055    }
1056    return (isset($presets_by_name[$preset_name])) ? $presets_by_name[$preset_name] : array();
1057  }
1058  
1059  /**
1060   * Save an ImageCache preset.
1061   *
1062   * @param preset
1063   *   an imagecache preset array.
1064   * @return
1065   *   a preset array.  In the case of a new preset, 'presetid' will be populated.
1066   */
1067  function imagecache_preset_save($preset) {
1068    // @todo: CRUD level validation?
1069    if (isset($preset['presetid']) && is_numeric($preset['presetid'])) {
1070      drupal_write_record('imagecache_preset', $preset, 'presetid');
1071    }
1072    else {
1073      drupal_write_record('imagecache_preset', $preset);
1074    }
1075  
1076    // Reset presets cache.
1077    imagecache_preset_flush($preset);
1078    imagecache_presets(TRUE);
1079  
1080    // Rebuild Theme Registry
1081    drupal_rebuild_theme_registry();
1082  
1083    return $preset;
1084  }
1085  
1086  function imagecache_preset_delete($preset) {
1087    imagecache_preset_flush($preset);
1088    db_query('DELETE FROM {imagecache_action} where presetid = %d', $preset['presetid']);
1089    db_query('DELETE FROM {imagecache_preset} where presetid = %d', $preset['presetid']);
1090    imagecache_presets(TRUE);
1091    return TRUE;
1092  }
1093  
1094  function imagecache_preset_actions($preset, $reset = FALSE) {
1095    static $actions_cache = array();
1096  
1097    if ($reset || empty($actions_cache[$preset['presetid']])) {
1098      $result = db_query('SELECT * FROM {imagecache_action} where presetid = %d order by weight', $preset['presetid']);
1099      while ($row = db_fetch_array($result)) {
1100        $row['data'] = unserialize($row['data']);
1101        $actions_cache[$preset['presetid']][] = $row;
1102      }
1103    }
1104  
1105    return isset($actions_cache[$preset['presetid']]) ? $actions_cache[$preset['presetid']] : array();
1106  }
1107  
1108  /**
1109   * Flush cached media for a preset.
1110   *
1111   * @param preset
1112   *   an imagecache preset array.
1113   */
1114  function imagecache_preset_flush($preset) {
1115    if (user_access('flush imagecache')) {
1116      $presetdir = realpath(file_directory_path() .'/imagecache/'. $preset['presetname']);
1117      if (is_dir($presetdir)) {
1118        module_invoke_all('imagecache_preset_flush', $presetdir, $preset);
1119        _imagecache_recursive_delete($presetdir);
1120      }
1121    }
1122  }
1123  
1124  /**
1125   * Clear cached versions of a specific file in all presets.
1126   * @param $path
1127   *   The Drupal file path to the original image.
1128   */
1129  function imagecache_image_flush($path) {
1130    foreach (imagecache_presets() as $preset) {
1131      $derivative_path = imagecache_create_path($preset['presetname'], $path);
1132      module_invoke_all('imagecache_image_flush', $derivative_path, $preset, $path);
1133      file_delete($derivative_path);
1134    }
1135  }
1136  
1137  function imagecache_action($actionid) {
1138    static $actions;
1139  
1140    if (!isset($actions[$actionid])) {
1141      $action = array();
1142  
1143      $result = db_query('SELECT * FROM {imagecache_action} WHERE actionid=%d', $actionid);
1144      if ($row = db_fetch_array($result)) {
1145        $action = $row;
1146        $action['data'] = unserialize($action['data']);
1147  
1148        $definition = imagecache_action_definition($action['action']);
1149        $action = array_merge($definition, $action);
1150        $actions[$actionid] = $action;
1151      }
1152    }
1153    return $actions[$actionid];
1154  }
1155  
1156  function imagecache_action_load($actionid) {
1157    return imagecache_action($actionid, TRUE);
1158  }
1159  
1160  function imagecache_action_save($action) {
1161    $definition = imagecache_action_definition($action['action']);
1162    $action = array_merge($definition, $action);
1163  
1164    // Some actions don't have data. Make an empty one to prevent SQL errors.
1165    if (!isset($action['data'])) {
1166      $action['data'] = array();
1167    }
1168  
1169    if (!empty($action['actionid'])) {
1170      drupal_write_record('imagecache_action', $action, 'actionid');
1171    }
1172    else {
1173      drupal_write_record('imagecache_action', $action);
1174    }
1175    $preset = imagecache_preset($action['presetid']);
1176    imagecache_preset_flush($preset);
1177    imagecache_presets(TRUE);
1178    return $action;
1179  }
1180  
1181  function imagecache_action_delete($action) {
1182    db_query('DELETE FROM {imagecache_action} WHERE actionid=%d', $action['actionid']);
1183    $preset = imagecache_preset($action['presetid']);
1184    imagecache_preset_flush($preset);
1185    imagecache_presets(TRUE);
1186  }
1187  
1188  /**
1189   * Implementation of hook_action_info().
1190   *
1191   * Note: These are actions in the Drupal core trigger.module sense, not
1192   * ImageCache actions.
1193   */
1194  function imagecache_action_info() {
1195    $actions = array();
1196  
1197    if (module_exists('filefield')) {
1198      $actions['imagecache_flush_action'] = array(
1199        'type' => 'node',
1200        'description' => t("ImageCache: Flush ALL presets for this node's filefield images"),
1201        'configurable' => FALSE,
1202        'hooks' => array(
1203          'nodeapi' => array('presave', 'delete', 'insert', 'update'),
1204        )
1205      );
1206      $actions['imagecache_generate_all_action'] = array(
1207        'type' => 'node',
1208        'description' => t("ImageCache: Generate ALL presets for this node's filefield images"),
1209        'configurable' => FALSE,
1210        'hooks' => array(
1211          'nodeapi' => array('presave', 'insert', 'update'),
1212        )
1213      );
1214      $actions['imagecache_generate_action'] = array(
1215        'type' => 'node',
1216        'description' => t("ImageCache: Generate configured preset(s) for this node's filefield images"),
1217        'configurable' => TRUE,
1218        'hooks' => array(
1219          'nodeapi' => array('presave', 'insert', 'update'),
1220        )
1221      );
1222    }
1223  
1224    return $actions;
1225  }
1226  
1227  /**
1228   * Flush all imagecache presets for a given node.
1229   *
1230   * @param $node
1231   *   A node object.
1232   * @param $context
1233   *   Contains values from the calling action.
1234   *
1235   * @see imagecache_action_info()
1236   */
1237  function imagecache_flush_action(&$node, $context) {
1238    $files = imagecache_get_images_in_node($node);
1239    if (!empty($files)) {
1240      foreach ($files as $file) {
1241        imagecache_image_flush($file['filepath']);
1242      }
1243    }
1244  }
1245  
1246  /**
1247   * Generate all imagecache presets for the given node.
1248   *
1249   * @param $node
1250   *   A node object.
1251   * @param $context
1252   *   Contains values from the calling action.
1253   *
1254   * @see imagecache_action_info()
1255   */
1256  function imagecache_generate_all_action(&$node, $context) {
1257    $files = imagecache_get_images_in_node($node);
1258    $presets = imagecache_presets();
1259    if (!empty($files) && !empty($presets)) {
1260      foreach ($files as $file) {
1261        foreach ($presets as $presetname) {
1262          imagecache_generate_image($presetname['presetname'], $file['filepath']);
1263        }
1264      }
1265    }
1266  }
1267  
1268  /**
1269   * Generate imagecache presets for the given node and presets.
1270   *
1271   * @param $node
1272   *   A node object.
1273   * @param $context
1274   *   Contains values from the calling action.
1275   *
1276   * @see imagecache_action_info()
1277   * @see imagecache_generate_action_form()
1278   */
1279  function imagecache_generate_action(&$node, $context) {
1280    $files = imagecache_get_images_in_node($node);
1281    if (!empty($files) && !empty($context['imagecache_presets'])) {
1282      foreach ($files as $file) {
1283        foreach ($context['imagecache_presets'] as $presetname) {
1284          imagecache_generate_image($presetname, $file['filepath']);
1285        }
1286      }
1287    }
1288  }
1289  
1290  /**
1291   * Form for configuring the generate action.
1292   *
1293   * @see imagecache_generate_action()
1294   */
1295  function imagecache_generate_action_form($context) {
1296    $options = array();
1297    foreach (imagecache_presets() as $preset) {
1298      $options[$preset['presetname']] = $preset['presetname'];
1299    }
1300    $form['presets'] = array(
1301      '#type' => 'checkboxes',
1302      '#options' => $options,
1303      '#description' => t('Select which imagecache presets will be effected'),
1304      '#required' => TRUE,
1305      '#default_value' => isset($context['imagecache_presets']) ? $context['imagecache_presets'] : array(),
1306    );
1307    // Filter out false checkboxes: http://drupal.org/node/61760#comment-402631
1308    $form['array_filter'] = array('#type' => 'value', '#value' => TRUE);
1309    return $form;
1310  }
1311  
1312  /**
1313   * Generate a derivative image given presetname and filepath.
1314   *
1315   * This is a developer friendly version of _imagecache_cache(), it doesn't worry
1316   * about sending HTTP headers or an image back to the client so it's much
1317   * simpler.
1318   *
1319   * @param $presetname
1320   *   ImageCache preset array.
1321   * @param $filepath
1322   *   String filepath from the files table.
1323   * @return
1324   *   A Boolean indicating if the operation succeeded.
1325   */
1326  function imagecache_generate_image($presetname, $filepath) {
1327    $preset = imagecache_preset_by_name($presetname);
1328    if (empty($preset['presetname'])) {
1329      return FALSE;
1330    }
1331    $destination = imagecache_create_path($preset['presetname'], $filepath);
1332    if (file_exists($destination)) {
1333      return TRUE;
1334    }
1335    return imagecache_build_derivative($preset['actions'], $filepath, $destination);
1336  }
1337  
1338  /**
1339   * Given a node, get all images associated with it.
1340   *
1341   * Currently this only works with images stored in filefields.
1342   *
1343   * @param $node
1344   *   Node object.
1345   * @return
1346   *   An array of info from the files table.
1347   */
1348  function imagecache_get_images_in_node(&$node) {
1349    $files = array();
1350    if (module_exists('filefield')) {
1351      $data = filefield_get_node_files($node);
1352      foreach ($data as $key => $value) {
1353        if (stristr($value['filemime'], 'image')) {
1354          $files[$key] = $value;
1355        }
1356      }
1357    }
1358    return $files;
1359  }
1360  


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7