cms/drupal/includes/image.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * API for manipulating images.
       
     6  */
       
     7 
       
     8 /**
       
     9  * @defgroup image Image toolkits
       
    10  * @{
       
    11  * Functions for image file manipulations.
       
    12  *
       
    13  * Drupal's image toolkits provide an abstraction layer for common image file
       
    14  * manipulations like scaling, cropping, and rotating. The abstraction frees
       
    15  * module authors from the need to support multiple image libraries, and it
       
    16  * allows site administrators to choose the library that's best for them.
       
    17  *
       
    18  * PHP includes the GD library by default so a GD toolkit is installed with
       
    19  * Drupal. Other toolkits like ImageMagick are available from contrib modules.
       
    20  * GD works well for small images, but using it with larger files may cause PHP
       
    21  * to run out of memory. In contrast the ImageMagick library does not suffer
       
    22  * from this problem, but it requires the ISP to have installed additional
       
    23  * software.
       
    24  *
       
    25  * Image toolkits are discovered based on the associated module's
       
    26  * hook_image_toolkits. Additionally the image toolkit include file
       
    27  * must be identified in the files array in the module.info file. The
       
    28  * toolkit must then be enabled using the admin/config/media/image-toolkit
       
    29  * form.
       
    30  *
       
    31  * Only one toolkit may be selected at a time. If a module author wishes to call
       
    32  * a specific toolkit they can check that it is installed by calling
       
    33  * image_get_available_toolkits(), and then calling its functions directly.
       
    34  */
       
    35 
       
    36 /**
       
    37  * Gets a list of available toolkits.
       
    38  *
       
    39  * @return
       
    40  *   An array with the toolkit names as keys and the descriptions as values.
       
    41  */
       
    42 function image_get_available_toolkits() {
       
    43   // hook_image_toolkits returns an array of toolkit names.
       
    44   $toolkits = module_invoke_all('image_toolkits');
       
    45 
       
    46   $output = array();
       
    47   foreach ($toolkits as $name => $info) {
       
    48     // Only allow modules that aren't marked as unavailable.
       
    49     if ($info['available']) {
       
    50       $output[$name] = $info['title'];
       
    51     }
       
    52   }
       
    53 
       
    54   return $output;
       
    55 }
       
    56 
       
    57 /**
       
    58  * Gets the name of the currently used toolkit.
       
    59  *
       
    60  * @return
       
    61  *   String containing the name of the selected toolkit, or FALSE on error.
       
    62  */
       
    63 function image_get_toolkit() {
       
    64   static $toolkit;
       
    65 
       
    66   if (!isset($toolkit)) {
       
    67     $toolkits = image_get_available_toolkits();
       
    68     $toolkit = variable_get('image_toolkit', 'gd');
       
    69     if (!isset($toolkits[$toolkit]) || !function_exists('image_' . $toolkit . '_load')) {
       
    70       // The selected toolkit isn't available so return the first one found. If
       
    71       // none are available this will return FALSE.
       
    72       reset($toolkits);
       
    73       $toolkit = key($toolkits);
       
    74     }
       
    75   }
       
    76 
       
    77   return $toolkit;
       
    78 }
       
    79 
       
    80 /**
       
    81  * Invokes the given method using the currently selected toolkit.
       
    82  *
       
    83  * @param $method
       
    84  *   A string containing the method to invoke.
       
    85  * @param $image
       
    86  *   An image object returned by image_load().
       
    87  * @param $params
       
    88  *   An optional array of parameters to pass to the toolkit method.
       
    89  *
       
    90  * @return
       
    91  *   Mixed values (typically Boolean indicating successful operation).
       
    92  */
       
    93 function image_toolkit_invoke($method, stdClass $image, array $params = array()) {
       
    94   $function = 'image_' . $image->toolkit . '_' . $method;
       
    95   if (function_exists($function)) {
       
    96     array_unshift($params, $image);
       
    97     return call_user_func_array($function, $params);
       
    98   }
       
    99   watchdog('image', 'The selected image handling toolkit %toolkit can not correctly process %function.', array('%toolkit' => $image->toolkit, '%function' => $function), WATCHDOG_ERROR);
       
   100   return FALSE;
       
   101 }
       
   102 
       
   103 /**
       
   104  * Gets details about an image.
       
   105  *
       
   106  * Drupal supports GIF, JPG and PNG file formats when used with the GD
       
   107  * toolkit, and may support others, depending on which toolkits are
       
   108  * installed.
       
   109  *
       
   110  * @param $filepath
       
   111  *   String specifying the path of the image file.
       
   112  * @param $toolkit
       
   113  *   An optional image toolkit name to override the default.
       
   114  *
       
   115  * @return
       
   116  *   FALSE, if the file could not be found or is not an image. Otherwise, a
       
   117  *   keyed array containing information about the image:
       
   118  *   - "width": Width, in pixels.
       
   119  *   - "height": Height, in pixels.
       
   120  *   - "extension": Commonly used file extension for the image.
       
   121  *   - "mime_type": MIME type ('image/jpeg', 'image/gif', 'image/png').
       
   122  *   - "file_size": File size in bytes.
       
   123  */
       
   124 function image_get_info($filepath, $toolkit = FALSE) {
       
   125   $details = FALSE;
       
   126   if (!is_file($filepath) && !is_uploaded_file($filepath)) {
       
   127     return $details;
       
   128   }
       
   129 
       
   130   if (!$toolkit) {
       
   131     $toolkit = image_get_toolkit();
       
   132   }
       
   133   if ($toolkit) {
       
   134     $image = new stdClass();
       
   135     $image->source = $filepath;
       
   136     $image->toolkit = $toolkit;
       
   137     $details = image_toolkit_invoke('get_info', $image);
       
   138     if (isset($details) && is_array($details)) {
       
   139       $details['file_size'] = filesize($filepath);
       
   140     }
       
   141   }
       
   142 
       
   143   return $details;
       
   144 }
       
   145 
       
   146 /**
       
   147  * Scales an image to the exact width and height given.
       
   148  *
       
   149  * This function achieves the target aspect ratio by cropping the original image
       
   150  * equally on both sides, or equally on the top and bottom. This function is
       
   151  * useful to create uniform sized avatars from larger images.
       
   152  *
       
   153  * The resulting image always has the exact target dimensions.
       
   154  *
       
   155  * @param $image
       
   156  *   An image object returned by image_load().
       
   157  * @param $width
       
   158  *   The target width, in pixels.
       
   159  * @param $height
       
   160  *   The target height, in pixels.
       
   161  *
       
   162  * @return
       
   163  *   TRUE on success, FALSE on failure.
       
   164  *
       
   165  * @see image_load()
       
   166  * @see image_resize()
       
   167  * @see image_crop()
       
   168  */
       
   169 function image_scale_and_crop(stdClass $image, $width, $height) {
       
   170   $scale = max($width / $image->info['width'], $height / $image->info['height']);
       
   171   $x = ($image->info['width'] * $scale - $width) / 2;
       
   172   $y = ($image->info['height'] * $scale - $height) / 2;
       
   173 
       
   174   if (image_resize($image, $image->info['width'] * $scale, $image->info['height'] * $scale)) {
       
   175     return image_crop($image, $x, $y, $width, $height);
       
   176   }
       
   177   return FALSE;
       
   178 }
       
   179 
       
   180 /**
       
   181  * Scales image dimensions while maintaining aspect ratio.
       
   182  *
       
   183  * The resulting dimensions can be smaller for one or both target dimensions.
       
   184  *
       
   185  * @param $dimensions
       
   186  *   Dimensions to be modified - an array with components width and height, in
       
   187  *   pixels.
       
   188  * @param $width
       
   189  *   The target width, in pixels. If this value is NULL then the scaling will be
       
   190  *   based only on the height value.
       
   191  * @param $height
       
   192  *   The target height, in pixels. If this value is NULL then the scaling will
       
   193  *   be based only on the width value.
       
   194  * @param $upscale
       
   195  *   Boolean indicating that images smaller than the target dimensions will be
       
   196  *   scaled up. This generally results in a low quality image.
       
   197  *
       
   198  * @return
       
   199  *   TRUE if $dimensions was modified, FALSE otherwise.
       
   200  *
       
   201  * @see image_scale()
       
   202  */
       
   203 function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NULL, $upscale = FALSE) {
       
   204   $aspect = $dimensions['height'] / $dimensions['width'];
       
   205 
       
   206   // Calculate one of the dimensions from the other target dimension,
       
   207   // ensuring the same aspect ratio as the source dimensions. If one of the
       
   208   // target dimensions is missing, that is the one that is calculated. If both
       
   209   // are specified then the dimension calculated is the one that would not be
       
   210   // calculated to be bigger than its target.
       
   211   if (($width && !$height) || ($width && $height && $aspect < $height / $width)) {
       
   212     $height = (int) round($width * $aspect);
       
   213   }
       
   214   else {
       
   215     $width = (int) round($height / $aspect);
       
   216   }
       
   217 
       
   218   // Don't upscale if the option isn't enabled.
       
   219   if (!$upscale && ($width >= $dimensions['width'] || $height >= $dimensions['height'])) {
       
   220     return FALSE;
       
   221   }
       
   222 
       
   223   $dimensions['width'] = $width;
       
   224   $dimensions['height'] = $height;
       
   225   return TRUE;
       
   226 }
       
   227 
       
   228 /**
       
   229  * Scales an image while maintaining aspect ratio.
       
   230  *
       
   231  * The resulting image can be smaller for one or both target dimensions.
       
   232  *
       
   233  * @param $image
       
   234  *   An image object returned by image_load().
       
   235  * @param $width
       
   236  *   The target width, in pixels. If this value is NULL then the scaling will
       
   237  *   be based only on the height value.
       
   238  * @param $height
       
   239  *   The target height, in pixels. If this value is NULL then the scaling will
       
   240  *   be based only on the width value.
       
   241  * @param $upscale
       
   242  *   Boolean indicating that files smaller than the dimensions will be scaled
       
   243  *   up. This generally results in a low quality image.
       
   244  *
       
   245  * @return
       
   246  *   TRUE on success, FALSE on failure.
       
   247  *
       
   248  * @see image_dimensions_scale()
       
   249  * @see image_load()
       
   250  * @see image_scale_and_crop()
       
   251  */
       
   252 function image_scale(stdClass $image, $width = NULL, $height = NULL, $upscale = FALSE) {
       
   253   $dimensions = $image->info;
       
   254 
       
   255   // Scale the dimensions - if they don't change then just return success.
       
   256   if (!image_dimensions_scale($dimensions, $width, $height, $upscale)) {
       
   257     return TRUE;
       
   258   }
       
   259 
       
   260   return image_resize($image, $dimensions['width'], $dimensions['height']);
       
   261 }
       
   262 
       
   263 /**
       
   264  * Resizes an image to the given dimensions (ignoring aspect ratio).
       
   265  *
       
   266  * @param $image
       
   267  *   An image object returned by image_load().
       
   268  * @param $width
       
   269  *   The target width, in pixels.
       
   270  * @param $height
       
   271  *   The target height, in pixels.
       
   272  *
       
   273  * @return
       
   274  *   TRUE on success, FALSE on failure.
       
   275  *
       
   276  * @see image_load()
       
   277  * @see image_gd_resize()
       
   278  */
       
   279 function image_resize(stdClass $image, $width, $height) {
       
   280   $width = (int) round($width);
       
   281   $height = (int) round($height);
       
   282 
       
   283   return image_toolkit_invoke('resize', $image, array($width, $height));
       
   284 }
       
   285 
       
   286 /**
       
   287  * Rotates an image by the given number of degrees.
       
   288  *
       
   289  * @param $image
       
   290  *   An image object returned by image_load().
       
   291  * @param $degrees
       
   292  *   The number of (clockwise) degrees to rotate the image.
       
   293  * @param $background
       
   294  *   An hexadecimal integer specifying the background color to use for the
       
   295  *   uncovered area of the image after the rotation. E.g. 0x000000 for black,
       
   296  *   0xff00ff for magenta, and 0xffffff for white. For images that support
       
   297  *   transparency, this will default to transparent. Otherwise it will
       
   298  *   be white.
       
   299  *
       
   300  * @return
       
   301  *   TRUE on success, FALSE on failure.
       
   302  *
       
   303  * @see image_load()
       
   304  * @see image_gd_rotate()
       
   305  */
       
   306 function image_rotate(stdClass $image, $degrees, $background = NULL) {
       
   307   return image_toolkit_invoke('rotate', $image, array($degrees, $background));
       
   308 }
       
   309 
       
   310 /**
       
   311  * Crops an image to a rectangle specified by the given dimensions.
       
   312  *
       
   313  * @param $image
       
   314  *   An image object returned by image_load().
       
   315  * @param $x
       
   316  *   The top left coordinate, in pixels, of the crop area (x axis value).
       
   317  * @param $y
       
   318  *   The top left coordinate, in pixels, of the crop area (y axis value).
       
   319  * @param $width
       
   320  *   The target width, in pixels.
       
   321  * @param $height
       
   322  *   The target height, in pixels.
       
   323  *
       
   324  * @return
       
   325  *   TRUE on success, FALSE on failure.
       
   326  *
       
   327  * @see image_load()
       
   328  * @see image_scale_and_crop()
       
   329  * @see image_gd_crop()
       
   330  */
       
   331 function image_crop(stdClass $image, $x, $y, $width, $height) {
       
   332   $aspect = $image->info['height'] / $image->info['width'];
       
   333   if (empty($height)) $height = $width / $aspect;
       
   334   if (empty($width)) $width = $height * $aspect;
       
   335 
       
   336   $width = (int) round($width);
       
   337   $height = (int) round($height);
       
   338 
       
   339   return image_toolkit_invoke('crop', $image, array($x, $y, $width, $height));
       
   340 }
       
   341 
       
   342 /**
       
   343  * Converts an image to grayscale.
       
   344  *
       
   345  * @param $image
       
   346  *   An image object returned by image_load().
       
   347  *
       
   348  * @return
       
   349  *   TRUE on success, FALSE on failure.
       
   350  *
       
   351  * @see image_load()
       
   352  * @see image_gd_desaturate()
       
   353  */
       
   354 function image_desaturate(stdClass $image) {
       
   355   return image_toolkit_invoke('desaturate', $image);
       
   356 }
       
   357 
       
   358 /**
       
   359  * Loads an image file and returns an image object.
       
   360  *
       
   361  * Any changes to the file are not saved until image_save() is called.
       
   362  *
       
   363  * @param $file
       
   364  *   Path to an image file.
       
   365  * @param $toolkit
       
   366  *   An optional, image toolkit name to override the default.
       
   367  *
       
   368  * @return
       
   369  *   An image object or FALSE if there was a problem loading the file. The
       
   370  *   image object has the following properties:
       
   371  *    - 'source' - The original file path.
       
   372  *    - 'info' - The array of information returned by image_get_info()
       
   373  *    - 'toolkit' - The name of the image toolkit requested when the image was
       
   374  *      loaded.
       
   375  *   Image toolkits may add additional properties. The caller is advised not to
       
   376  *   monkey about with them.
       
   377  *
       
   378  * @see image_save()
       
   379  * @see image_get_info()
       
   380  * @see image_get_available_toolkits()
       
   381  * @see image_gd_load()
       
   382  */
       
   383 function image_load($file, $toolkit = FALSE) {
       
   384   if (!$toolkit) {
       
   385     $toolkit = image_get_toolkit();
       
   386   }
       
   387   if ($toolkit) {
       
   388     $image = new stdClass();
       
   389     $image->source = $file;
       
   390     $image->info = image_get_info($file, $toolkit);
       
   391     if (isset($image->info) && is_array($image->info)) {
       
   392       $image->toolkit = $toolkit;
       
   393       if (image_toolkit_invoke('load', $image)) {
       
   394         return $image;
       
   395       }
       
   396     }
       
   397   }
       
   398   return FALSE;
       
   399 }
       
   400 
       
   401 /**
       
   402  * Closes the image and saves the changes to a file.
       
   403  *
       
   404  * @param $image
       
   405  *   An image object returned by image_load(). The object's 'info' property
       
   406  *   will be updated if the file is saved successfully.
       
   407  * @param $destination
       
   408  *   Destination path where the image should be saved. If it is empty the
       
   409  *   original image file will be overwritten.
       
   410  *
       
   411  * @return
       
   412  *   TRUE on success, FALSE on failure.
       
   413  *
       
   414  * @see image_load()
       
   415  * @see image_gd_save()
       
   416  */
       
   417 function image_save(stdClass $image, $destination = NULL) {
       
   418   if (empty($destination)) {
       
   419     $destination = $image->source;
       
   420   }
       
   421   if ($return = image_toolkit_invoke('save', $image, array($destination))) {
       
   422     // Clear the cached file size and refresh the image information.
       
   423     clearstatcache();
       
   424     $image->info = image_get_info($destination, $image->toolkit);
       
   425 
       
   426     if (drupal_chmod($destination)) {
       
   427       return $return;
       
   428     }
       
   429   }
       
   430   return FALSE;
       
   431 }
       
   432 
       
   433 /**
       
   434  * @} End of "defgroup image".
       
   435  */