| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
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 » Site configuration » 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
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |