summaryrefslogtreecommitdiff
path: root/includes/image.inc
blob: 44eca9f3c7c5082aaff3fa61b8c88638d2e8eaa4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<?php
// $Id$

/**
 * @file
 * API for manipulating images.
 */

/**
 * @defgroup image Image toolkits
 * @{
 * Drupal's image toolkits provide an abstraction layer for common image file
 * manipulations like scaling, cropping, and rotating. The abstraction frees
 * module authors from the need to support multiple image libraries, and it
 * allows site administrators to choose the library that's best for them.
 *
 * PHP includes the GD library by default so a GD toolkit is installed with
 * Drupal. Other toolkits like ImageMagic are available from contrib modules.
 * GD works well for small images, but using it with larger files may cause PHP
 * to run out of memory. In contrast the ImageMagick library does not suffer
 * from this problem, but it requires the ISP to have installed additional
 * software.
 *
 * Image toolkits are discovered based on the associated module's
 * hook_image_toolkits. Additionally the image toolkit include file
 * must be identified in the files array in the module.info file.  The
 * toolkit must then be enabled using the admin/settings/image-toolkit
 * form.
 *
 * Only one toolkit may be selected at a time. If a module author wishes to call
 * a specific toolkit they can check that it is installed by calling
 * image_get_available_toolkits(), and then calling its functions directly.
 */

/**
 * Return a list of available toolkits.
 *
 * @return
 *   An array of toolkit name => descriptive title.
 */
function image_get_available_toolkits() {
  // hook_image_toolkits returns an array of toolkit names.
  $toolkits = module_invoke_all('image_toolkits');

  $output = array();
  foreach ($toolkits as $name) {
    $function = 'image_' . $name . '_info';
    if (drupal_function_exists($function)) {
      $info = $function();
      $output[$info['name']] = $info['title'];
    }
  }
  return $output;
}

/**
 * Retrieve the name of the currently used toolkit.
 *
 * @return
 *   String containing the name of the selected toolkit, or FALSE on error.
 */
function image_get_toolkit() {
  static $toolkit;

  if (!$toolkit) {
    $toolkit = variable_get('image_toolkit', 'gd');
    if (isset($toolkit) &&
      drupal_function_exists("image_" . $toolkit . "_resize")) {
    }
    elseif (!drupal_function_exists("image_gd_check_settings") ||
      !image_gd_check_settings()) {
      $toolkit = FALSE;
    }
  }

  return $toolkit;
}

/**
 * Invokes the given method using the currently selected toolkit.
 *
 * @param $method
 *   A string containing the method to invoke.
 * @param $params
 *   An optional array of parameters to pass to the toolkit method.
 * @return
 *   Mixed values (typically Boolean indicating successful operation).
 */
function image_toolkit_invoke($method, $params = array()) {
  if ($toolkit = image_get_toolkit()) {
    $function = 'image_' . $toolkit . '_' . $method;
    if (drupal_function_exists($function)) {
      return call_user_func_array($function, $params);
    }
    else {
      watchdog('php', 'The selected image handling toolkit %toolkit can not correctly process %function.', array('%toolkit' => $toolkit, '%function' => $function), WATCHDOG_ERROR);
      return FALSE;
    }
  }
}


/**
 * Get details about an image.
 *
 * Drupal only supports GIF, JPG and PNG file formats.
 *
 * @return
 *   FALSE, if the file could not be found or is not an image. Otherwise, a
 *   keyed array containing information about the image:
 *    'width'     - Width in pixels.
 *    'height'    - Height in pixels.
 *    'extension' - Commonly used file extension for the image.
 *    'mime_type' - MIME type ('image/jpeg', 'image/gif', 'image/png').
 *    'file_size' - File size in bytes.
 */
function image_get_info($file) {
  if (!is_file($file)) {
    return FALSE;
  }

  $details = FALSE;
  $data = @getimagesize($file);
  $file_size = @filesize($file);

  if (isset($data) && is_array($data)) {
    $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
    $extension = array_key_exists($data[2], $extensions) ?  $extensions[$data[2]] : '';
    $details = array('width'     => $data[0],
                     'height'    => $data[1],
                     'extension' => $extension,
                     'file_size' => $file_size,
                     'mime_type' => $data['mime']);
  }

  return $details;
}

/**
 * Scales an image to the exact width and height given. Achieves the
 * target aspect ratio by cropping the original image equally on both
 * sides, or equally on the top and bottom.  This function is, for
 * example, useful to create uniform sized avatars from larger images.
 *
 * The resulting image always has the exact target dimensions.
 *
 * @param $source
 *   The file path of the source image.
 * @param $destination
 *   The file path of the destination image.
 * @param $width
 *   The target width, in pixels.
 * @param $height
 *   The target height, in pixels.
 * @return
 *   TRUE or FALSE, based on success.
 */
function image_scale_and_crop($source, $destination, $width, $height) {
  $info = image_get_info($source);

  $scale = max($width / $info['width'], $height / $info['height']);
  $x = round(($info['width'] * $scale - $width) / 2);
  $y = round(($info['height'] * $scale - $height) / 2);

  if (image_toolkit_invoke('resize', array($source, $destination, $info['width'] * $scale, $info['height'] * $scale))) {
    return image_toolkit_invoke('crop', array($destination, $destination, $x, $y, $width, $height));
  }
  return FALSE;
}

/**
 * Scales an image to the given width and height while maintaining aspect
 * ratio.
 *
 * The resulting image can be smaller for one or both target dimensions.
 *
 * @param $source
 *   The file path of the source image.
 * @param $destination
 *   The file path of the destination image.
 * @param $width
 *   The target width, in pixels.
 * @param $height
 *   The target height, in pixels.
 * @return
 *   TRUE or FALSE, based on success.
 */
function image_scale($source, $destination, $width, $height) {
  $info = image_get_info($source);

  // Don't scale up.
  if ($width >= $info['width'] && $height >= $info['height']) {
    return FALSE;
  }

  $aspect = $info['height'] / $info['width'];
  if ($aspect < $height / $width) {
    $width = (int)min($width, $info['width']);
    $height = (int)round($width * $aspect);
  }
  else {
    $height = (int)min($height, $info['height']);
    $width = (int)round($height / $aspect);
  }

  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
}

/**
 * Resize an image to the given dimensions (ignoring aspect ratio).
 *
 * @param $source
 *   The file path of the source image.
 * @param $destination
 *   The file path of the destination image.
 * @param $width
 *   The target width, in pixels.
 * @param $height
 *   The target height, in pixels.
  * @return
 *   TRUE or FALSE, based on success.
 */
function image_resize($source, $destination, $width, $height) {
  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
}

/**
 * Rotate an image by the given number of degrees.
 *
 * @param $source
 *   The file path of the source image.
 * @param $destination
 *   The file path of the destination image.
 * @param $degrees
 *   The number of (clockwise) degrees to rotate the image.
 * @param $background
 *   An hexidecimal integer specifying the background color to use for the
 *   uncovered area of the image after the rotation. E.g. 0x000000 for black,
 *   0xff00ff for magenta, and 0xffffff for white.
 * @return
 *   TRUE or FALSE, based on success.
 */
function image_rotate($source, $destination, $degrees, $background = 0x000000) {
  return image_toolkit_invoke('rotate', array($source, $destination, $degrees, $background));
}

/**
 * Crop an image to the rectangle specified by the given rectangle.
 *
 * @param $source
 *   The file path of the source image.
 * @param $destination
 *   The file path of the destination image.
 * @param $x
 *   The top left co-ordinate, in pixels, of the crop area (x axis value).
 * @param $y
 *   The top left co-ordinate, in pixels, of the crop area (y axis value).
 * @param $width
 *   The target width, in pixels.
 * @param $height
 *   The target height, in pixels.
 * @return
 *   TRUE or FALSE, based on success.
 */
function image_crop($source, $destination, $x, $y, $width, $height) {
  return image_toolkit_invoke('crop', array($source, $destination, $x, $y, $width, $height));
}

/**
 * @} End of "defgroup image".
 */