[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

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

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


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7