[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

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

   1  <?php
   2  // $Id: image.module,v 1.322.2.4 2010/08/18 16:40:06 joachim Exp $
   3  
   4  define('IMAGE_ORIGINAL', '_original');
   5  define('IMAGE_PREVIEW', 'preview');
   6  define('IMAGE_THUMBNAIL', 'thumbnail');
   7  
   8  define('IMAGE_LINK_HIDDEN', 0);
   9  define('IMAGE_LINK_SHOWN', 1);
  10  define('IMAGE_LINK_NEW', 2);
  11  
  12  /**
  13   * Implementation of hook_help().
  14   */
  15  function image_help($path, $arg) {
  16    switch ($path) {
  17      case 'admin/help#image':
  18        $output = '<p>' . t('The Image module is used to create and administer images for your site. Each image is stored as a post, with thumbnails of the original generated automatically. There are two default derivative image sizes, "thumbnail" and "preview". The "thumbnail" size is shown as preview image in posts and when browsing image galleries. The "preview" size is the default size when viewing an image node page.') . '</p>';
  19        $output .= '<p>' . t('The settings page for Image module allows the image directory and the image sizes to be configured.') . '</p>';
  20        $output .= '<p>' . t('Image module ships with contributed modules. Their settings can be accessed from the image settings page.') . '</p>';
  21        $output .= '<ul>';
  22        $output .= '<li>' . t('Image attach is used to add an existing or new image to a node. The selected image will show up in a predefined spot on the selected node.') . '</li>';
  23        $output .= '<li>' . t('Image gallery is used to organize and display images in galleries. The list tab allows users to edit existing image gallery names, descriptions, parents and relative position, known as a weight. The add galleries tab allows you to create a new image gallery defining name, description, parent and weight. If the <a href="@views-url">Views module</a> is installed, then the Image gallery module settings are mostly replaced by settings of the view.', array('@views-url' => 'http://drupal.org/project/views')) . '</li>';
  24        $output .= '<li>' . t('Image import is used to import batches of images. The administration page lets you define the folder from which images will be imported.') . '</li>';
  25        $output .= '<li>' . t('The separate <a href="@img-assist-url">Image assist module</a> can be installed to upload and insert images into posts.', array('@img-assist-url' => 'http://drupal.org/project/img_assist')) . '</li>';
  26        $output .= '</ul>';
  27        $output .= '<p>' . t('You can:') . '</p>';
  28        $output .= '<ul>';
  29        $output .= '<li>' . t('Configure image sizes and file directories at <a href="@image-settings-url">Administer &raquo; Site configuration &raquo; Image</a>.', array('@image-settings-url' => url('admin/settings/image'))) . '</li>';
  30        $output .= '</ul>';
  31        $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@image-url">Image module</a>.', array('@image-url' => 'http://drupal.org/handbook/modules/image')) . '</p>';
  32        return $output;
  33    }
  34  }
  35  
  36  /**
  37   * Implementation of hook_theme().
  38   */
  39  function image_theme() {
  40    return array(
  41      'image_settings_sizes_form' => array(
  42        'arguments' => array('form' => NULL),
  43      ),
  44      'image_teaser' => array(
  45        'arguments' => array('node' => NULL, 'size' => IMAGE_THUMBNAIL),
  46      ),
  47      'image_body' => array(
  48        'arguments' => array('node' => NULL, 'size' => IMAGE_PREVIEW),
  49      ),
  50      'image_block_random' => array(
  51        'arguments' => array('images' => NULL, 'size' => IMAGE_THUMBNAIL),
  52      ),
  53      'image_block_latest' => array(
  54        'arguments' => array('images' => NULL, 'size' => IMAGE_THUMBNAIL),
  55      ),
  56      'image_display' => array(
  57        'arguments' => array(
  58          'node' => NULL,
  59          'label' => NULL,
  60          'url' => NULL,
  61          'attributes' => NULL,
  62        ),
  63      ),
  64    );
  65  }
  66  
  67  /**
  68   * Implementation of hook_node_info
  69   */
  70  function image_node_info() {
  71    return array(
  72      'image' => array(
  73        'name' => t('Image'),
  74        'module' => 'image',
  75        'description' => t('An image (with thumbnail). This is ideal for publishing photographs or screenshots.'),
  76      ),
  77    );
  78  }
  79  
  80  /**
  81   * Implementation of hook_perm
  82   */
  83  function image_perm() {
  84    return array('view original images', 'create images', 'edit own images', 'edit any images', 'delete own images', 'delete any images');
  85  }
  86  
  87  /**
  88   * Implementation of hook_access().
  89   */
  90  function image_access($op, $node, $account) {
  91    switch ($op) {
  92      case 'create':
  93        if (user_access('create images', $account)) {
  94          return TRUE;
  95        }
  96        break;
  97  
  98      case 'update':
  99        if (user_access('edit any images', $account) || ($account->uid == $node->uid && user_access('edit own images', $account))) {
 100          return TRUE;
 101        }
 102        break;
 103  
 104      case 'delete':
 105        if (user_access('delete any images', $account) || ($account->uid == $node->uid && user_access('delete own images', $account))) {
 106          return TRUE;
 107        }
 108        break;
 109    }
 110  }
 111  
 112  /**
 113   * Implementation of hook_menu
 114   */
 115  function image_menu() {
 116    $items = array();
 117  
 118    $items['image/view'] = array(
 119      'title' => 'image',
 120      'access arguments' => array('access content'),
 121      'type' => MENU_CALLBACK,
 122      'page callback' => 'image_fetch',
 123    );
 124    $items['admin/settings/image'] = array(
 125      'title' => 'Images',
 126      'description' => 'Configure the location of image files and image sizes. Also, if enabled, configure image attachments and options for image galleries and image imports.',
 127      'page callback' => 'drupal_get_form',
 128      'page arguments' => array('image_admin_settings'),
 129      'access arguments' => array('administer site configuration'),
 130      'type' => MENU_NORMAL_ITEM,
 131      'file' => 'image.admin.inc',
 132    );
 133    $items['admin/settings/image/nodes'] = array(
 134      'title' => 'Files and sizes',
 135      'description' => 'Configure the location of image files and image sizes.',
 136      'access arguments' => array('administer site configuration'),
 137      'type' => MENU_DEFAULT_LOCAL_TASK,
 138      'weight' => '-10',
 139    );
 140  
 141    return $items;
 142  }
 143  
 144  /**
 145   * Implements hook_cron. (deletes old temp images)
 146   */
 147  function image_cron() {
 148    $path = file_directory_path() . '/' . variable_get('image_default_path', 'images') . '/temp';
 149    $files = file_scan_directory(file_create_path($path), '.*');
 150    foreach ($files as $file => $info) {
 151      if (time() - filemtime($file) > 60 * 60 * 6) {
 152        file_delete($file);
 153      }
 154    }
 155  }
 156  
 157  /**
 158   * Implementation of hook_node_operations().
 159   */
 160  function image_node_operations() {
 161    $operations = array(
 162      'rebuild_thumbs' => array(
 163        'label' => t('Rebuild derivative images'),
 164        'callback' => 'image_operations_rebuild',
 165      ),
 166    );
 167    return $operations;
 168  }
 169  
 170  function image_operations_rebuild($nids) {
 171    foreach ($nids as $nid) {
 172      if ($node = node_load($nid)) {
 173        if ($node->type == 'image') {
 174          $node->rebuild_images = TRUE;
 175          image_update($node);
 176        }
 177      }
 178    }
 179  }
 180  
 181  /**
 182   * Implementation of hook_file_download().
 183   *
 184   * Note that in Drupal 5, the upload.module's hook_file_download() checks its
 185   * permissions for all files in the {files} table. We store our file
 186   * information in {files} if private files transfers are selected and the
 187   * upload.module is enabled, users will the 'view uploaded files' permission to
 188   * view images.
 189   */
 190  function image_file_download($filename) {
 191    $filepath = file_create_path($filename);
 192    $result = db_query("SELECT i.nid, f.filemime, f.filesize FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE f.filepath = '%s'", $filepath);
 193    if ($file = db_fetch_object($result)) {
 194      $node = node_load(array('type' => 'image', 'nid' => $file->nid));
 195      if (node_access('view', $node)) {
 196        // The user either needs to have 'view original images' permission or
 197        // the path must be listed for something other than the node's original
 198        // size. This will be the case when the orignal is smaller than a
 199        // derivative size.
 200        $images = (array) $node->images;
 201        unset($images[IMAGE_ORIGINAL]);
 202        if (user_access('view original images') || in_array($filepath, $images)) {
 203          return array(
 204            'Content-Type: ' . mime_header_encode($file->filemime),
 205            'Content-Length: ' . (int) $file->filesize,
 206          );
 207        }
 208      }
 209      return -1;
 210    }
 211  }
 212  
 213  /**
 214   * Implementation of hook_link.
 215   */
 216  function image_link($type, $node, $main = 0) {
 217    $links = array();
 218  
 219    if ($type == 'node' && $node->type == 'image' && !$main) {
 220      $request = isset($_GET['size']) ? $_GET['size'] : IMAGE_PREVIEW;
 221      foreach (image_get_sizes() as $key => $size) {
 222        if ($size['link']) {
 223          // For smaller images some derivative images may not have been created.
 224          // The thumbnail and preview images will be equal to the original images
 225          // but other sizes will not be set.
 226          if (isset($node->images[$key]) && $node->images[$key] != $node->images[$request]) {
 227            if ($size['link'] == IMAGE_LINK_NEW) {
 228              $links['image_size_' . $key] = array(
 229                'title' => t($size['label']),
 230                'href' => "image/view/{$node->nid}/$key",
 231                'attributes' => array('target' => '_blank'),
 232              );
 233            }
 234            else {
 235              $links['image_size_' . $key] = array(
 236                'title' => t($size['label']),
 237                'href' => 'node/' . $node->nid,
 238                'query' => 'size=' . urlencode($key),
 239              );
 240            }
 241          }
 242        }
 243      }
 244      if (!user_access('view original images')) {
 245        unset($links['image_size_' . IMAGE_ORIGINAL]);
 246      }
 247    }
 248  
 249    return $links;
 250  }
 251  
 252  /**
 253   * Implementation of hook_block.
 254   *
 255   * Offers 2 blocks: latest image and random image
 256   */
 257  function image_block($op = 'list', $delta = 0, $edit = array()) {
 258    switch ($op) {
 259      case 'list':
 260        $block[0]['info'] = t('Latest image');
 261        $block[1]['info'] = t('Random image');
 262        return $block;
 263  
 264      case 'configure':
 265        $form['number_images'] = array(
 266          '#type' => 'select',
 267          '#title' => t('Number of images to display'),
 268          '#options' => drupal_map_assoc(range(1, 99)),
 269          '#default_value' => variable_get("image_block_{$delta}_number_images", 1),
 270        );
 271        return $form;
 272  
 273      case 'view':
 274        if (user_access('access content')) {
 275          switch ($delta) {
 276            case 0:
 277              $images = image_get_latest(variable_get("image_block_{$delta}_number_images", 1));
 278              $block['subject'] = t('Latest image');
 279              $block['content'] = theme('image_block_latest', $images, IMAGE_THUMBNAIL);
 280              break;
 281  
 282            case 1:
 283              $images = image_get_random(variable_get("image_block_{$delta}_number_images", 1));
 284              $block['subject'] = t('Random image');
 285              $block['content'] = theme('image_block_random', $images, IMAGE_THUMBNAIL);
 286              break;
 287          }
 288        }
 289        return $block;
 290  
 291      case 'save':
 292        variable_set("image_block_{$delta}_number_images", $edit['number_images']);
 293        break;
 294    }
 295  }
 296  
 297  function image_form_add_thumbnail($form, &$form_state) {
 298    if ($form_state['values']['images'][IMAGE_THUMBNAIL]) {
 299      $node = (object)($form_state['values']);
 300      $form['#title'] = t('Thumbnail');
 301      $form['#value'] = image_display($node, IMAGE_THUMBNAIL);
 302    }
 303    return $form;
 304  }
 305  
 306  /**
 307   * Implementation of hook_form().
 308   */
 309  function image_form(&$node, $form_state) {
 310    _image_check_settings();
 311  
 312    if (!$_POST && !empty($_SESSION['image_upload'])) {
 313      unset($_SESSION['image_upload']);
 314    }
 315  
 316    $type = node_get_types('type', $node);
 317  
 318    $form['#validate'][] = 'image_form_validate';
 319    $form['#submit'][] = 'image_form_submit';
 320  
 321    $form['title'] = array(
 322      '#type' => 'textfield',
 323      '#title' => check_plain($type->title_label),
 324      '#size' => 60,
 325      '#maxlength' => 128,
 326      '#required' => TRUE,
 327      '#default_value' => $node->title,
 328    );
 329  
 330    $form['images']['#tree'] = TRUE;
 331    foreach (image_get_sizes() as $key => $size) {
 332      $form['images'][$key] = array(
 333        '#type' => 'value',
 334        '#value' => isset($node->images[$key]) ? $node->images[$key] : '',
 335      );
 336    }
 337  
 338    $form['new_file'] = array(
 339      '#type' => 'value',
 340      '#default_value' => isset($node->new_file) ? $node->new_file : FALSE,
 341    );
 342  
 343    $form['#attributes'] = array('enctype' => 'multipart/form-data');
 344  
 345    $form['image'] = array(
 346      '#prefix' => '<div class="image-field-wrapper">',
 347      '#suffix' => '</div>',
 348    );
 349    $form['image']['thumbnail'] = array(
 350      '#type' => 'item',
 351      '#after_build' => array('image_form_add_thumbnail'),
 352    );
 353    $form['image']['image'] = array(
 354      '#type' => 'file',
 355      '#title' => t('Image'),
 356      '#size' => 40,
 357      '#description' => t('Select an image to upload.'),
 358    );
 359    $form['image']['rebuild_images'] = array(
 360      '#type' => 'checkbox',
 361      '#title' => t('Rebuild derivative images'),
 362      '#default_value' => FALSE,
 363      '#description' => t('Check this to rebuild the derivative images for this node.'),
 364      '#access' => (!isset($node->nid) ? FALSE : TRUE),
 365    );
 366  
 367    if ($type->has_body) {
 368      $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
 369    }
 370  
 371    return $form;
 372  }
 373  
 374  function image_form_validate($form, &$form_state) {
 375    // Avoid blocking node deletion with missing image.
 376    if ($form_state['values']['op'] == t('Delete')) {
 377      return;
 378    }
 379  
 380    // Validators for file_save_upload().
 381    $validators = array(
 382      'file_validate_is_image' => array(),
 383    );
 384  
 385    // New image uploads need to be saved in images/temp in order to be viewable
 386    // during node preview.
 387    $temporary_file_path = file_create_path(file_directory_path() . '/' . variable_get('image_default_path', 'images') . '/temp');
 388  
 389    if ($file = file_save_upload('image', $validators, $temporary_file_path)) {
 390      // Resize the original.
 391      $image_info = image_get_info($file->filepath);
 392      $aspect_ratio = $image_info['height'] / $image_info['width'];
 393      $original_size = image_get_sizes(IMAGE_ORIGINAL, $aspect_ratio);
 394      if (!empty($original_size['width']) && !empty($original_size['height'])) {
 395        $result = image_scale($file->filepath, $file->filepath, $original_size['width'], $original_size['height']);
 396        if ($result) {
 397          clearstatcache();
 398          $file->filesize = filesize($file->filepath);
 399          drupal_set_message(t('The original image was resized to fit within the maximum allowed resolution of %width x %height pixels.', array('%width' => $original_size['width'], '%height' => $original_size['height'])));
 400        }
 401      }
 402  
 403      // Check the file size limit.
 404      if ($file->filesize > variable_get('image_max_upload_size', 800) * 1024) {
 405        form_set_error('image', t('The image you uploaded was too big. You are only allowed upload files less than %max_size but your file was %file_size.', array('%max_size' => format_size(variable_get('image_max_upload_size', 800) * 1024), '%file_size' => format_size($file->filesize))));
 406        file_delete($file->filepath);
 407        return;
 408      }
 409  
 410      // We're good to go.
 411      $form_state['values']['images'][IMAGE_ORIGINAL] = $file->filepath;
 412      $form_state['values']['rebuild_images'] = FALSE;
 413      $form_state['values']['new_file'] = TRUE;
 414  
 415      // Call hook to allow other modules to modify the original image.
 416      module_invoke_all('image_alter', $form_state['values'], $form_state['values']['images'][IMAGE_ORIGINAL], IMAGE_ORIGINAL);
 417      $form_state['values']['images'] = _image_build_derivatives((object) $form_state['values'], TRUE);
 418  
 419      // Store the new file into the session.
 420      $_SESSION['image_upload'] = $form_state['values']['images'];
 421    }
 422    elseif (empty($form_state['values']['images'][IMAGE_ORIGINAL])) {
 423      if (empty($_SESSION['image_upload'])) {
 424        form_set_error('image', t('You must upload an image.'));
 425      }
 426    }
 427  }
 428  
 429  function image_form_submit($form, &$form_state) {
 430    if (!empty($_SESSION['image_upload'])) {
 431      $form_state['values']['images'] = $_SESSION['image_upload'];
 432      $form_state['values']['new_file'] = TRUE;
 433      unset($_SESSION['image_upload']);
 434    }
 435  }
 436  
 437  /**
 438   * Implementation of hook_view
 439   */
 440  function image_view($node, $teaser = 0, $page = 0) {
 441    $sizes = image_get_sizes();
 442    $size = IMAGE_PREVIEW;
 443    if (isset($_GET['size'])) {
 444      // Invalid size specified.
 445      if (!isset($sizes[$_GET['size']])) {
 446        drupal_goto("node/$node->nid");
 447      }
 448      $size = $_GET['size'];
 449      // Not allowed to view the original.
 450      if ($size == IMAGE_ORIGINAL && !user_access('view original images')) {
 451        drupal_goto("node/$node->nid");
 452      }
 453    }
 454  
 455    $node = node_prepare($node, $teaser);
 456    $node->content['image'] = array(
 457      '#value' => theme($teaser ? 'image_teaser' : 'image_body', $node, $size),
 458      '#weight' => 0,
 459    );
 460  
 461    return $node;
 462  }
 463  
 464  /**
 465   * Implementation of hook_load().
 466   */
 467  function image_load(&$node) {
 468    $result = db_query("SELECT i.image_size, f.filepath FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE i.nid = %d", $node->nid);
 469    $node->images = array();
 470    while ($file = db_fetch_object($result)) {
 471      $node->images[$file->image_size] = file_create_path($file->filepath);
 472    }
 473  
 474    $original_path = (isset($node->images[IMAGE_ORIGINAL]) ? $node->images[IMAGE_ORIGINAL] : NULL);
 475    if (empty($original_path)) {
 476      // There's no original image, we're in trouble...
 477      return;
 478    }
 479  
 480    if ((arg(0) != 'batch') && (strpos($_GET['q'], 'admin/content/node') === FALSE)) {
 481      _image_build_derivatives_if_needed($node);
 482    }
 483  }
 484  
 485  /**
 486   * Rebuild derivatives if needed. Helper function for image_load().
 487   */
 488  function _image_build_derivatives_if_needed(&$node) {
 489    $node->rebuild_images = FALSE;
 490  
 491    // Figure out which sizes should have been generated.
 492    $all_sizes = image_get_sizes();
 493    unset($all_sizes[IMAGE_ORIGINAL]);
 494    $needed_sizes = array_keys(image_get_derivative_sizes($node->images[IMAGE_ORIGINAL]));
 495    $unneeded_sizes = array_diff(array_keys($all_sizes), $needed_sizes);
 496  
 497    // Derivative sizes that are larger than the original get set to the
 498    // original.
 499    foreach ($unneeded_sizes as $key) {
 500      if (empty($node->images[$key])) {
 501        $node->images[$key] = $node->images[IMAGE_ORIGINAL];
 502      }
 503      else {
 504        // Need to remove an extra derivative image in the database.
 505        $node->rebuild_images = TRUE;
 506      }
 507    }
 508  
 509    // Check that the derivative images are present and current.
 510    foreach ($needed_sizes as $key) {
 511      // If the file is missing or created after the last change to the sizes,
 512      // rebuild the derivatives.
 513      if (empty($node->images[$key]) || !file_exists($node->images[$key])) {
 514        $node->rebuild_images = TRUE;
 515      }
 516      // Derivative image had a timestamp that predates last changes to image
 517      // size settings, so it needs to be rebuilt.
 518      elseif (filemtime($node->images[$key]) < variable_get('image_updated', 0)) {
 519        $node->rebuild_images = TRUE;
 520      }
 521    }
 522  
 523    // Correct any problems with the derivative images.
 524    if ($node->rebuild_images) {
 525      // Possibly TODO: calling a hook implementation here isn't very elegant.
 526      // but the code there is tangled and it works, so maybe leave it ;)
 527      image_update($node);
 528      watchdog('image', 'Derivative images were regenerated for %title.', array('%title' => $node->title), WATCHDOG_INFO, l(t('view'), 'node/' . $node->nid));
 529    }
 530  }
 531  
 532  /**
 533   * Implementation of hook_insert().
 534   */
 535  function image_insert($node) {
 536    // If a new image node contains no new file, but has a translation source,
 537    // insert all images from the source for this node.
 538    if (empty($node->new_file) && !empty($node->translation_source)) {
 539      db_query("INSERT INTO {image} (nid, fid, image_size) SELECT %d, fid, image_size FROM {image} WHERE nid = %d", $node->nid, $node->translation_source->nid);
 540      return;
 541    }
 542  
 543    // Derivative images that aren't needed are set to the original file. Make
 544    // note of the current path before calling _image_insert() because if it's
 545    // in the temp directory it'll be moved. We'll need it later to determine
 546    // which derivative images need to be saved with _image_insert().
 547    $original_path = $node->images[IMAGE_ORIGINAL];
 548  
 549    // Save the original first so that it if it's moved the derivatives are
 550    // placed in the correct directory.
 551    _image_insert($node, IMAGE_ORIGINAL, $original_path);
 552  
 553    $sizes = image_get_derivative_sizes($node->images[IMAGE_ORIGINAL]);
 554    foreach ($sizes as $key => $size_info) {
 555      if (!empty($node->images[$key]) && $node->images[$key] != $original_path) {
 556        _image_insert($node, $key, $node->images[$key]);
 557      }
 558    }
 559  }
 560  
 561  /**
 562   * Implementation of hook_update().
 563   *
 564   * Take $node by reference so we can use this to save the node after
 565   * rebuilding derivatives.
 566   */
 567  function image_update(&$node) {
 568    if (!empty($node->new_file) || !empty($node->rebuild_images)) {
 569      // Derivative images that aren't needed are set to the original file. Make
 570      // note of the current path before calling _image_insert() because if it's
 571      // in the temp directory it'll be moved. We'll need it later to determine
 572      // which derivative images need to be saved with _image_insert().
 573      $original_path = $node->images[IMAGE_ORIGINAL];
 574  
 575      if (!empty($node->new_file)) {
 576        // The derivative images were built during image_prepare() or
 577        // image_create_node_from() so all we need to do is remove all the old,
 578        // existing images.
 579  
 580        // Remove all the existing images.
 581        $result = db_query("SELECT f.fid, f.filepath FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE i.nid = %d", $node->nid);
 582        while ($file = db_fetch_object($result)) {
 583          db_query("DELETE FROM {image} WHERE nid = %d AND fid = %d", $node->nid, $file->fid);
 584          _image_file_remove($file);
 585        }
 586  
 587        // Save the original first so that it if it's moved the derivatives are
 588        // placed in the correct directory.
 589        _image_insert($node, IMAGE_ORIGINAL, $original_path);
 590      }
 591      else if (!empty($node->rebuild_images)) {
 592        // Find the original image.
 593        $original_file = db_fetch_object(db_query("SELECT i.fid, f.filepath FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE i.nid = %d AND i.image_size = '%s'", $node->nid, IMAGE_ORIGINAL));
 594  
 595        // Delete all but the original image.
 596        $result = db_query("SELECT i.fid, f.filepath FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE i.nid = %d AND f.fid <> %d", $node->nid, $original_file->fid);
 597        while ($file = db_fetch_object($result)) {
 598          db_query("DELETE FROM {image} WHERE nid = %d AND fid = %d", $node->nid, $file->fid);
 599          // Beware of derivative images that have the same path as the original.
 600          if ($file->filepath != $original_file->filepath) {
 601            _image_file_remove($file);
 602          }
 603        }
 604  
 605        $node->images = _image_build_derivatives($node, FALSE);
 606  
 607        // Prevent multiple rebuilds.
 608        $node->rebuild_images = FALSE;
 609      }
 610  
 611      $sizes = image_get_derivative_sizes($node->images[IMAGE_ORIGINAL]);
 612      foreach ($sizes as $key => $size_info) {
 613        if (!empty($node->images[$key]) && $node->images[$key] != $original_path) {
 614          _image_insert($node, $key, $node->images[$key]);
 615        }
 616      }
 617    }
 618  }
 619  
 620  /**
 621   * Implementation of hook_delete().
 622   */
 623  function image_delete($node) {
 624    $result = db_query('SELECT i.fid, f.filepath FROM {image} i INNER JOIN {files} f ON i.fid = f.fid WHERE i.nid = %d', $node->nid);
 625    while ($file = db_fetch_object($result)) {
 626      db_query("DELETE FROM {image} WHERE nid = %d AND fid = %d", $node->nid, $file->fid);
 627      _image_file_remove($file);
 628    }
 629  }
 630  
 631  /**
 632   * Create an <img> tag for an image.
 633   */
 634  function image_display(&$node, $label = IMAGE_PREVIEW, $attributes = array()) {
 635    if (empty($node->images[$label])) {
 636      return;
 637    }
 638  
 639    $image_info = image_get_info(file_create_path($node->images[$label]));
 640    $attributes['class'] = "image image-$label " . (isset($attributes['class']) ? $attributes['class'] : "");
 641    // Only output width/height attributes if image_get_info() was able to detect
 642    // the image dimensions, since certain browsers interpret an empty attribute
 643    // value as zero.
 644    if (!empty($image_info['width'])) {
 645      $attributes['width'] = $image_info['width'];
 646    }
 647    if (!empty($image_info['height'])) {
 648      $attributes['height'] = $image_info['height'];
 649    }
 650  
 651    return theme('image_display', $node, $label, file_create_url($node->images[$label]), $attributes);
 652  }
 653  
 654  /**
 655   * Fetches an image file, allows "shorthand" image urls such of the form:
 656   * image/view/$nid/$label
 657   * (e.g. image/view/25/thumbnail or image/view/14)
 658   */
 659  function image_fetch($nid = 0, $size = IMAGE_PREVIEW) {
 660    if ($size == IMAGE_ORIGINAL && !user_access('view original images')) {
 661      return drupal_access_denied();
 662    }
 663  
 664    if (isset($nid)) {
 665      $node = node_load(array('type' => 'image', 'nid' => $nid));
 666      if ($node) {
 667        if (!node_access('view', $node)) {
 668          return drupal_access_denied();
 669        }
 670  
 671        if (isset($node->images[$size])) {
 672          $file = $node->images[$size];
 673          $headers = module_invoke_all('file_download', $file);
 674          if ($headers == -1) {
 675            return drupal_access_denied();
 676          }
 677          file_transfer($file, $headers);
 678        }
 679      }
 680    }
 681    return drupal_not_found();
 682  }
 683  
 684  /**
 685   * Theme a teaser
 686   */
 687  function theme_image_teaser($node, $size) {
 688    return l(image_display($node, IMAGE_THUMBNAIL), 'node/' . $node->nid, array('html' => TRUE));
 689  }
 690  
 691  /**
 692   * Theme a body
 693   */
 694  function theme_image_body($node, $size) {
 695    return image_display($node, $size);
 696  }
 697  
 698  /**
 699   * Theme an img tag for displaying the image.
 700   */
 701  function theme_image_display($node, $label, $url, $attributes) {
 702    $title = isset($attributes['title']) ? $attributes['title'] : $node->title;
 703    $alt = isset($attributes['alt']) ? $attributes['alt'] : $node->title;
 704    // Remove alt and title from $attributes, otherwise they get added to the img tag twice.
 705    unset($attributes['title']);
 706    unset($attributes['alt']);
 707    return theme('image', $url, $alt, $title, $attributes, FALSE);
 708  }
 709  
 710  /**
 711   * Theme a random block
 712   */
 713  function theme_image_block_random($images, $size) {
 714    $output = '';
 715    foreach ($images as $image) {
 716      $output .= l(image_display($image, $size), 'node/' . $image->nid, array('html' => TRUE));
 717    }
 718    return $output;
 719  }
 720  
 721  /**
 722   * Theme a latest block
 723   */
 724  function theme_image_block_latest($images, $size) {
 725    $output = '';
 726    foreach ($images as $image) {
 727      $output .= l(image_display($image, $size), 'node/' . $image->nid, array('html' => TRUE));
 728    }
 729    return $output;
 730  }
 731  
 732  /**
 733   * Fetch a random N image(s) - optionally from a given term.
 734   */
 735  function image_get_random($count = 1, $tid = 0) {
 736    if ($tid != 0) {
 737      $result = db_query_range(db_rewrite_sql("SELECT DISTINCT(n.nid), RAND() AS rand FROM {term_node} tn LEFT JOIN {node} n ON n.nid = tn.nid WHERE n.type='image' AND n.status = 1 AND tn.tid = %d ORDER BY rand"), $tid, 0, $count);
 738    }
 739    else {
 740      $result = db_query_range(db_rewrite_sql("SELECT DISTINCT(n.nid), RAND() AS rand FROM {node} n WHERE n.type = 'image' AND n.status = 1 ORDER BY rand"), 0, $count);
 741    }
 742    $output = array();
 743    while ($nid = db_fetch_object($result)) {
 744      $output[] = node_load(array('nid' => $nid->nid));
 745    }
 746    return $output;
 747  }
 748  
 749  /**
 750   * Fetch the latest N image(s) - optionally from a given term.
 751   */
 752  function image_get_latest($count = 1, $tid = 0) {
 753    if ($tid != 0) {
 754      $result = db_query_range(db_rewrite_sql("SELECT n.nid FROM {term_node} tn LEFT JOIN {node} n ON n.nid=tn.nid WHERE n.type='image' AND n.status=1 AND tn.tid=%d ORDER BY n.changed DESC"), $tid, 0, $count);
 755    }
 756    else {
 757      $result = db_query_range(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.type = 'image' AND n.status = 1 ORDER BY n.changed DESC"), 0, $count);
 758    }
 759    $output = array();
 760    while ($nid = db_fetch_object($result)) {
 761      $output[] = node_load(array('nid' => $nid->nid));
 762    }
 763    return $output;
 764  }
 765  
 766  /**
 767   * Verify the image module and toolkit settings.
 768   */
 769  function _image_check_settings() {
 770    // File paths
 771    $image_path = file_create_path(file_directory_path() . '/' . variable_get('image_default_path', 'images'));
 772    $temp_path = $image_path . '/temp';
 773  
 774    if (!file_check_directory($image_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS, 'image_default_path')) {
 775      return FALSE;
 776    }
 777    if (!file_check_directory($temp_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS, 'image_default_path')) {
 778      return FALSE;
 779    }
 780  
 781    // Sanity check : make sure we've got a working toolkit
 782    if (!image_get_toolkit()) {
 783      drupal_set_message(t('No image toolkit is currently enabled. Without one the image module will not be able to resize your images. You can select one from the <a href="@link">image toolkit settings page</a>.', array('@link' => url('admin/settings/image-toolkit'))), 'error');
 784      return FALSE;
 785    }
 786    return TRUE;
 787  }
 788  
 789  /**
 790   * Determine which sizes of derivative images need to be built for this image.
 791   *
 792   * @param $image_path
 793   *   String file path to the image.
 794   *
 795   * @return
 796   *   Returns a subset of image_get_sizes()'s results depending on what
 797   *   derivative images are needed.
 798   */
 799  function image_get_derivative_sizes($image_path) {
 800    $sizes = array();
 801  
 802    // Can't do much if we can't read the image.
 803    if (!$image_info = image_get_info($image_path)) {
 804      return $sizes;
 805    }
 806  
 807    $all_sizes = image_get_sizes(NULL, $image_info['height'] / $image_info['width']);
 808    foreach ($all_sizes as $key => $size) {
 809      // We don't want to include the original.
 810      if ($key == IMAGE_ORIGINAL) {
 811        continue;
 812      }
 813  
 814      // If the original isn't bigger than the requested size then there's no
 815      // need to resize it.
 816      if ($image_info['width'] > $size['width'] || $image_info['height'] > $size['height']) {
 817        $sizes[$key] = $size;
 818      }
 819    }
 820  
 821    return $sizes;
 822  }
 823  
 824  /**
 825   * Generate image derivatives.
 826   *
 827   * @param $node
 828   *   The node.
 829   * @param $temp
 830   *   Boolean indicating if the derivatives should be saved to the temp
 831   *   directory.
 832   *
 833   * @return
 834   *   New array of images for the node.
 835   */
 836  function _image_build_derivatives($node, $temp = FALSE) {
 837    $original_path = file_create_path($node->images[IMAGE_ORIGINAL]);
 838  
 839    // Figure out which sizes we need to generate.
 840    $all_sizes      = image_get_sizes();
 841    $needed_sizes   = image_get_derivative_sizes($original_path);
 842    $unneeded_sizes = array_diff(array_keys($all_sizes), array_keys($needed_sizes));
 843  
 844    // Images that don't need a derivative image get set to the original.
 845    $images[IMAGE_ORIGINAL] = $original_path;
 846    foreach ($unneeded_sizes as $key) {
 847      $images[$key] = $original_path;
 848    }
 849  
 850    // Resize for the necessary sizes.
 851    $image_info = image_get_info($original_path);
 852    foreach ($needed_sizes as $key => $size) {
 853      $destination = _image_filename($original_path, $key, $temp);
 854  
 855      $status = FALSE;
 856      switch ($size['operation']) {
 857        // Depending on the operation, the image will be scaled or resized & cropped
 858        case 'scale':
 859          $status = image_scale($original_path, $destination, $size['width'], $size['height']);
 860          break;
 861  
 862        case 'scale_crop':
 863          $status = image_scale_and_crop($original_path, $destination, $size['width'], $size['height']);
 864          break;
 865      }
 866  
 867      if (!$status) {
 868        drupal_set_message(t('Unable to create scaled %label image.', array('%label' => $size['label'])), 'error');
 869        return FALSE;
 870      }
 871      // Set standard file permissions for webserver-generated files
 872      @chmod($destination, 0664);
 873  
 874      $images[$key] = $destination;
 875      module_invoke_all('image_alter', $node, $destination, $key);
 876    }
 877  
 878    return $images;
 879  }
 880  
 881  /**
 882   * Creates an image filename.
 883   *
 884   * @param $filepath
 885   *   The full path and filename of the original image file,relative to Drupal
 886   *   root, eg 'sites/default/files/images/myimage.jpg'.
 887   *
 888   * @return
 889   *   A full path and filename with derivative image label inserted if required.
 890   */
 891  function _image_filename($filepath, $label = IMAGE_ORIGINAL, $temp = FALSE) {
 892    // Get default path for a new file.
 893    $path = file_directory_path() . '/' . variable_get('image_default_path', 'images');
 894    if ($temp) {
 895      $path .= '/temp';
 896    }
 897  
 898    $original_path = dirname($filepath);
 899    $filename = basename($filepath);
 900  
 901    if ($label && ($label != IMAGE_ORIGINAL)) {
 902      // Keep resized images in the same path, where original is (does not
 903      // apply to temporary files, these still use the default path).
 904      if (!$temp && $original_path != '.') {
 905        $path = $original_path;
 906      }
 907      // Insert the resized name in non-original images.
 908      $pos = strrpos($filename, '.');
 909      if ($pos === FALSE) {
 910        // The file had no extension - which happens in really old image.module
 911        // versions, so figure out the extension.
 912        $image_info = image_get_info(file_create_path($path . '/' . $filename));
 913        $filename = $filename . '.' . $label . '.' . $image_info['extension'];
 914      }
 915      else {
 916        $filename = substr($filename, 0, $pos) . '.' . $label . substr($filename, $pos);
 917      }
 918    }
 919  
 920    return file_create_path($path . '/' . $filename);
 921  }
 922  
 923  /**
 924   * Helper function to return the defined sizes (or proper defaults).
 925   *
 926   * @param $size
 927   *   An optional string to return only the image size with the specified key.
 928   * @param $aspect_ratio
 929   *   Float value with the ratio of image height / width. If a size has only one
 930   *   dimension provided this will be used to compute the other.
 931   *
 932   * @return
 933   *   An associative array with width, height, and label fields for the size.
 934   *   If a $size parameter was specified and it cannot be found FALSE will be
 935   *   returned.
 936   */
 937  function image_get_sizes($size = NULL, $aspect_ratio = NULL) {
 938    $defaults = array(
 939      IMAGE_ORIGINAL => array('width' => '', 'height' => '', 'label' => t('Original'), 'operation' => 'scale', 'link' => IMAGE_LINK_SHOWN),
 940      IMAGE_THUMBNAIL => array('width' => 100, 'height' => 100, 'label' => t('Thumbnail'), 'operation' => 'scale', 'link' => IMAGE_LINK_SHOWN),
 941      IMAGE_PREVIEW => array('width' => 640, 'height' => 640, 'label' => t('Preview'), 'operation' => 'scale', 'link' => IMAGE_LINK_SHOWN),
 942    );
 943  
 944    $sizes = array();
 945    foreach (variable_get('image_sizes', $defaults) as $key => $val) {
 946      // Only return sizes with a label.
 947      if (!empty($val['label'])) {
 948        // For a size with only one dimension specified, compute the other
 949        // dimension based on an aspect ratio.
 950        if ($aspect_ratio && (empty($val['width']) || empty($val['height']))) {
 951          if (empty($val['height']) && !empty($val['width'])) {
 952            $val['height'] = (int)round($val['width'] * $aspect_ratio);
 953          }
 954          elseif (empty($val['width']) && !empty($val['height'])) {
 955            $val['width'] = (int)round($val['height'] / $aspect_ratio);
 956          }
 957        }
 958        $sizes[$key] = $val;
 959      }
 960    }
 961  
 962    // If they requested a specific size return only that.
 963    if (isset($size)) {
 964      // Only return an array if it's available.
 965      return isset($sizes[$size]) ? $sizes[$size] : FALSE;
 966    }
 967  
 968    return $sizes;
 969  }
 970  
 971  /**
 972   * Helper function to preserve backwards compatibility. This has been
 973   * deprecated in favor of image_get_sizes().
 974   *
 975   * @TODO: Remove this in a future version.
 976   */
 977  function _image_get_sizes($size = NULL, $aspect_ratio = NULL) {
 978    return image_get_sizes($size, $aspect_ratio);
 979  }
 980  
 981  /**
 982   * Is a given size a built-in, required size?
 983   *
 984   * @param $size
 985   *   One of the keys in the array returned by image_get_sizes().
 986   *
 987   * @return boolean
 988   */
 989  function _image_is_required_size($size) {
 990    return in_array($size, array(IMAGE_THUMBNAIL, IMAGE_PREVIEW, IMAGE_ORIGINAL));
 991  }
 992  
 993  /**
 994   * Moves temporary (working) images to the final directory and stores
 995   * relevant information in the files table
 996   */
 997  function _image_insert(&$node, $size, $image_path) {
 998    $original_path = $node->images[IMAGE_ORIGINAL];
 999    if (file_move($image_path, _image_filename($original_path, $size))) {
1000      // Update the node to reflect the actual filename, it may have been changed
1001      // if a file of the same name already existed.
1002      $node->images[$size] = $image_path;
1003  
1004      $image_info = image_get_info($image_path);
1005      $file = array(
1006        'uid' => $node->uid,
1007        'filename' => $size,
1008        'filepath' => $image_path,
1009        'filemime' => $image_info['mime_type'],
1010        'filesize' => $image_info['file_size'],
1011        'status' => FILE_STATUS_PERMANENT,
1012        'timestamp' => time(),
1013      );
1014      drupal_write_record('files', $file);
1015      $image = array(
1016        'fid' => $file['fid'],
1017        'nid' => $node->nid,
1018        'image_size' => $size,
1019      );
1020      drupal_write_record('image', $image);
1021    }
1022  }
1023  
1024  /**
1025   * Remove image file if no other node references it.
1026   *
1027   * @param $file
1028   *   An object representing a table row from {files}.
1029   */
1030  function _image_file_remove($file) {
1031    if (!db_result(db_query("SELECT COUNT(*) FROM {image} WHERE fid = %d", $file->fid))) {
1032      file_delete(file_create_path($file->filepath));
1033      db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
1034    }
1035  }
1036  
1037  /**
1038   * Function to other modules to use to create image nodes.
1039   *
1040   * @param $filepath
1041   *   String filepath of an image file. Note that this file will be moved into
1042   *   the image module's images directory.
1043   * @param $title
1044   *   String to be used as the node's title. If this is ommitted the filename
1045   *   will be used.
1046   * @param $body
1047   *   String to be used as the node's body.
1048   * @param $taxonomy
1049   *   Taxonomy terms to assign to the node if the taxonomy.module is installed.
1050   * @param $keep_original
1051   *   Boolean to indicate whether the original file should be deleted
1052   *
1053   * @return
1054   *   A node object if the node is created successfully or FALSE on error.
1055   */
1056  function image_create_node_from($filepath, $title = NULL, $body = '', $taxonomy = NULL, $keep_original = FALSE) {
1057    global $user;
1058  
1059    if (!user_access('create images')) {
1060      return FALSE;
1061    }
1062  
1063    // Ensure it's a valid image.
1064    if (!$image_info = image_get_info($filepath)) {
1065      return FALSE;
1066    }
1067  
1068    // Ensure the file is within our size bounds.
1069    if ($image_info['file_size'] > variable_get('image_max_upload_size', 800) * 1024) {
1070      form_set_error('', t('The image you uploaded was too big. You are only allowed upload files less than %max_size but your file was %file_size.', array('%max_size' => format_size(variable_get('image_max_upload_size', 800) * 1024), '%file_size' => format_size($image_info['file_size']))), 'warning');
1071      return FALSE;
1072    }
1073  
1074    // Make sure we can copy the file into our temp directory.
1075    $original_path = $filepath;
1076    if (!file_copy($filepath, _image_filename($filepath, IMAGE_ORIGINAL, TRUE))) {
1077      return FALSE;
1078    }
1079  
1080    // Resize the original image.
1081    $aspect_ratio = $image_info['height'] / $image_info['width'];
1082    $size = image_get_sizes(IMAGE_ORIGINAL, $aspect_ratio);
1083    if (!empty($size['width']) && !empty($size['height'])) {
1084      image_scale($filepath, $filepath, $size['width'], $size['height']);
1085    }
1086  
1087    // Build the node.
1088    $node = new stdClass();
1089    $node->type = 'image';
1090    $node->uid = $user->uid;
1091    $node->name = $user->name;
1092    $node->title = isset($title) ? $title : basename($filepath);
1093    $node->body = $body;
1094  
1095    // Set the node's defaults... (copied this from node and comment.module)
1096    $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
1097    $node->status = in_array('status', $node_options);
1098    $node->promote = in_array('promote', $node_options);
1099    if (module_exists('comment')) {
1100      $node->comment = variable_get("comment_$node->type", COMMENT_NODE_READ_WRITE);
1101    }
1102    if (module_exists('taxonomy')) {
1103      $node->taxonomy = $taxonomy;
1104    }
1105  
1106    $node->new_file = TRUE;
1107    $node->images[IMAGE_ORIGINAL] = $filepath;
1108  
1109    // Save the node.
1110    $node = node_submit($node);
1111    node_save($node);
1112  
1113    // By default, remove the original image now that the import has completed.
1114    if ($keep_original !== TRUE) {
1115      file_delete($original_path);
1116    }
1117  
1118    return $node;
1119  }
1120  
1121  /**
1122   * Implementation of hook_views_api().
1123   */
1124  function image_views_api() {
1125    return array(
1126      'api' => 2,
1127      'path' => drupal_get_path('module', 'image') . '/views',
1128    );
1129  }
1130  
1131  /**
1132   * Implementation of hook_content_extra_fields().
1133   *
1134   * Lets CCK expose the image weight in the node content.
1135   */
1136  function image_content_extra_fields($type_name) {
1137    if ($type_name == 'image') {
1138      $extra['image'] = array(
1139        'label' => t('Image'),
1140        'description' => t('Image display.'),
1141        'weight' => 0,
1142      );
1143      return $extra;
1144    }
1145  }
1146  


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