| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: imageapi.module,v 1.23.2.4 2010/04/30 21:48:38 drewish Exp $ 3 4 /** 5 * @file 6 * 7 * An ImageAPI supporting additional image plugins as modules. 8 * Images are treated as objects, and images are not written per 9 * manipulation as Drupal's core image handling works. 10 * 11 * 12 * imageapi image api workflow... 13 * $image = imageapi_image_open($path) to get an image object for $path... 14 * image_X($image, $arg1, $arg2) to manipulate image object... 15 * imageapi_image_close($image) to overwrite original image. 16 * 17 */ 18 19 /** 20 * Implementation of hook_perm(). 21 */ 22 function imageapi_perm() { 23 return array('administer imageapi'); 24 } 25 26 /** 27 * Implementation of hook_menu(). 28 */ 29 function imageapi_menu() { 30 $items = array(); 31 $items['admin/settings/imageapi'] = array( 32 'title' => 'ImageAPI', 33 'description' => 'Configure ImageAPI.', 34 'page callback' => 'drupal_get_form', 35 'page arguments' => array('imageapi_settings'), 36 'access arguments' => array('administer imageapi'), 37 ); 38 39 $toolkits = imageapi_get_available_toolkits(); 40 if ($toolkits) { 41 $items['admin/settings/imageapi/list'] = array( 42 'title' => 'List', 43 'type' => MENU_DEFAULT_LOCAL_TASK, 44 'weight' => -1, 45 ); 46 $items['admin/settings/imageapi/config'] = array( 47 'title' => 'Configure', 48 'type' => MENU_LOCAL_TASK, 49 'page callback' => 'drupal_get_form', 50 'page arguments' => array(imageapi_default_toolkit() .'_settings_form'), 51 'access arguments' => array('administer imageapi'), 52 ); 53 foreach ($toolkits as $module => $info) { 54 if (function_exists($module .'_settings_form')) { 55 $items['admin/settings/imageapi/config/'. $module] = array( 56 'title' => '@name', 57 'title arguments' => array('@name' => $info['name']), 58 'page callback' => 'drupal_get_form', 59 'page arguments' => array($module .'_settings_form'), 60 'access arguments' => array('administer imageapi'), 61 'type' => $module == imageapi_default_toolkit() ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, 62 ); 63 } 64 else { 65 drupal_set_message(t('ImageAPI toolkit missing settings form'), 'error'); 66 } 67 } 68 } 69 return $items; 70 } 71 72 function imageapi_settings() { 73 $form = array(); 74 75 $toolkits = imageapi_get_available_toolkits(); 76 77 switch (count($toolkits)) { 78 case 0: 79 $form['imageapi_toolkits']['#value'] = t('There are no image toolkit modules enabled. Toolkit modules can be enabled from the <a href="!admin-build-modules">module configuration page</a>.', array('!admin-build-modules' => url('admin/build/modules'))); 80 return $form; 81 82 case 1: 83 $toolkit = key($toolkits); 84 // The variable needs to be manually set. Otherwise, if a user has two 85 // toolkits and disables the selected one they won't be able to select the 86 // remaing toolkit. 87 variable_set('imageapi_image_toolkit', $toolkit); 88 $form['imageapi_image_toolkit']['#value'] = t('The %toolkit module is the only enabled image toolkit. Drupal will use it for resizing, cropping and other image manipulations.', array('%toolkit' => $toolkits[$toolkit]['name'])); 89 return $form; 90 91 default: 92 $options = array(); 93 foreach ($toolkits as $module => $info) { 94 $options[$module] = $info['name']; 95 } 96 $form['imageapi_image_toolkit'] = array( 97 '#type' => 'radios', 98 '#title' => t('Select a default image processing toolkit'), 99 '#default_value' => imageapi_default_toolkit(), 100 '#options' => $options, 101 '#description' => t('This setting lets you choose which toolkit Drupal uses resizing, cropping and other image manipulations.'), 102 ); 103 } 104 105 return system_settings_form($form); 106 } 107 108 /** 109 * Return a list of available toolkits. 110 * 111 * @return 112 * An array of the enabled image toolkit modules. The module name is the key 113 * and the value is a sub-array with the module's 'name' and 'description'. 114 */ 115 function imageapi_get_available_toolkits() { 116 static $toolkits; 117 118 if (!isset($toolkits)) { 119 $toolkits = array(); 120 foreach (module_implements('imageapi_toolkit', TRUE) as $module) { 121 $info = drupal_parse_info_file(drupal_get_path('module', $module) .'/'. $module .'.info'); 122 $toolkits[$module] = array('name' => $info['name'], 'description' => $info['description']); 123 } 124 } 125 126 return $toolkits; 127 } 128 129 /** 130 * Retrieve the name of the currently used toolkit. 131 * 132 * @return 133 * String containing the name of the toolkit, or FALSE if none is available. 134 */ 135 function imageapi_default_toolkit() { 136 $toolkit = variable_get('imageapi_image_toolkit', 'imageapi_gd'); 137 // Verify that the image toolkit is available. 138 if (isset($toolkit) && module_exists($toolkit)) { 139 return $toolkit; 140 } 141 // If it's not fall back to first available toolist. 142 foreach (imageapi_get_available_toolkits() as $toolkit => $info) { 143 return $toolkit; 144 } 145 return FALSE; 146 } 147 148 149 /** 150 * Invokes the given method using the currently selected toolkit. 151 * 152 * @param $method 153 * A string containing the method to invoke. 154 * @param $image 155 * An image object returned by imageapi_image_open(). 156 * @param $params 157 * An optional array of parameters to pass to the toolkit method. 158 * @return 159 * Mixed values (typically Boolean indicating successful operation). 160 */ 161 function imageapi_toolkit_invoke($method, &$image, array $params = array()) { 162 $function = $image->toolkit . '_image_' . $method; 163 if (function_exists($function)) { 164 array_unshift($params, $image); 165 $params[0] = &$image; 166 return call_user_func_array($function, $params); 167 } 168 watchdog('imageapi', 'The selected image handling toolkit %toolkit can not correctly process %function.', array('%toolkit' => $image->toolkit, '%function' => $function), WATCHDOG_ERROR); 169 return FALSE; 170 } 171 172 /** 173 * Scales an image to the exact width and height given. 174 * 175 * This function achieves the target aspect ratio by cropping the original image 176 * equally on both sides, or equally on the top and bottom. This function is 177 * useful to create uniform sized avatars from larger images. 178 * 179 * The resulting image always has the exact target dimensions. 180 * 181 * @param $image 182 * An image object returned by imageapi_image_open(). 183 * @param $width 184 * The target width, in pixels. 185 * @param $height 186 * The target height, in pixels. 187 * @return 188 * TRUE or FALSE, based on success. 189 */ 190 function imageapi_image_scale_and_crop(&$image, $width, $height) { 191 $scale = max($width / $image->info['width'], $height / $image->info['height']); 192 $x = ($image->info['width'] * $scale - $width) / 2; 193 $y = ($image->info['height'] * $scale - $height) / 2; 194 195 if (imageapi_image_resize($image, $image->info['width'] * $scale, $image->info['height'] * $scale)) { 196 return imageapi_image_crop($image, $x, $y, $width, $height); 197 } 198 return FALSE; 199 } 200 201 /** 202 * Scales an image to the given width and height while maintaining aspect 203 * ratio. 204 * 205 * The resulting image can be smaller for one or both target dimensions. 206 * 207 * @param $image 208 * An image object returned by imageapi_image_open(). 209 * @param $width 210 * The target width, in pixels. This value is omitted then the scaling will 211 * based only on the height value. 212 * @param $height 213 * The target height, in pixels. This value is omitted then the scaling will 214 * based only on the width value. 215 * @param $upscale 216 * Boolean indicating that files smaller than the dimensions will be scalled 217 * up. This generally results in a low quality image. 218 * @return 219 * TRUE or FALSE, based on success. 220 */ 221 function imageapi_image_scale(&$image, $width = NULL, $height = NULL, $upscale = FALSE) { 222 $aspect = $image->info['height'] / $image->info['width']; 223 224 if ($upscale) { 225 // Set width/height according to aspect ratio if either is empty. 226 $width = !empty($width) ? $width : $height / $aspect; 227 $height = !empty($height) ? $height : $width / $aspect; 228 } 229 else { 230 // Set impossibly large values if the width and height aren't set. 231 $width = !empty($width) ? $width : 9999999; 232 $height = !empty($height) ? $height : 9999999; 233 234 // Don't scale up. 235 if (round($width) >= $image->info['width'] && round($height) >= $image->info['height']) { 236 return TRUE; 237 } 238 } 239 240 if ($aspect < $height / $width) { 241 $height = $width * $aspect; 242 } 243 else { 244 $width = $height / $aspect; 245 } 246 247 return imageapi_image_resize($image, $width, $height); 248 } 249 250 /** 251 * Resize an image to the given dimensions (ignoring aspect ratio). 252 * 253 * @param $image 254 * An image object returned by imageapi_image_open(). 255 * @param $width 256 * The target width, in pixels. 257 * @param $height 258 * The target height, in pixels. 259 * @return 260 * TRUE or FALSE, based on success. 261 */ 262 function imageapi_image_resize(&$image, $width, $height) { 263 $width = (int) round($width); 264 $height = (int) round($height); 265 266 return imageapi_toolkit_invoke('resize', $image, array($width, $height)); 267 } 268 269 /** 270 * Rotate an image by the given number of degrees. 271 * 272 * @param $image 273 * An image object returned by imageapi_image_open(). 274 * @param $degrees 275 * The number of (clockwise) degrees to rotate the image. 276 * @param $background 277 * An hexadecimal integer specifying the background color to use for the 278 * uncovered area of the image after the rotation. E.g. 0x000000 for black, 279 * 0xff00ff for magenta, and 0xffffff for white. For images that support 280 * transparency, this will default to transparent. Otherwise it will 281 * be white. 282 * @return 283 * TRUE or FALSE, based on success. 284 */ 285 function imageapi_image_rotate(&$image, $degrees, $background = NULL) { 286 return imageapi_toolkit_invoke('rotate', $image, array($degrees, $background)); 287 } 288 289 /** 290 * Sharpen an image given some sharpening parameters. 291 * 292 * NOTE: These parameters only have an effect when Imagemagick is used. 293 * GD will used a fixed convolution matrix as described in imageapi_gd.module 294 * 295 * @param $image 296 * An imageapi image object returned by imageapi_image_open(). 297 * @param $radius 298 * The radius of the gaussian, in pixels, not counting the center pixel. (default 0.5) 299 * @param $sigma 300 * The standard deviation of the gaussian, in pixels. (default 0.5) 301 * @param $amount 302 * The percentage of the difference between the original and the blur image that is 303 * added back into the original. (default 100) 304 * @param $threshold 305 * The threshold, as a fraction of max RGB levels, needed to apply the difference 306 * amount. (default 0.05) 307 * @return 308 * True or FALSE, based on success. 309 */ 310 function imageapi_image_sharpen(&$image, $radius, $sigma, $amount, $threshold) { 311 return imageapi_toolkit_invoke('sharpen', $image, array($radius, $sigma, $amount, $threshold)); 312 } 313 314 /** 315 * Crop an image to the rectangle specified by the given rectangle. 316 * 317 * @param $image 318 * An image object returned by imageapi_image_open(). 319 * @param $x 320 * The top left coordinate, in pixels, of the crop area (x axis value). 321 * @param $y 322 * The top left coordinate, in pixels, of the crop area (y axis value). 323 * @param $width 324 * The target width, in pixels. 325 * @param $height 326 * The target height, in pixels. 327 * @return 328 * TRUE or FALSE, based on success. 329 */ 330 function imageapi_image_crop(&$image, $x, $y, $width, $height) { 331 $aspect = $image->info['height'] / $image->info['width']; 332 if (empty($height)) $height = $width / $aspect; 333 if (empty($width)) $width = $height * $aspect; 334 335 $width = (int) round($width); 336 $height = (int) round($height); 337 338 return imageapi_toolkit_invoke('crop', $image, array($x, $y, $width, $height)); 339 } 340 341 /** 342 * Convert an image to grayscale. 343 * 344 * @param $image 345 * An image object returned by imageapi_image_open(). 346 * @return 347 * TRUE or FALSE, based on success. 348 */ 349 function imageapi_image_desaturate(&$image) { 350 return imageapi_toolkit_invoke('desaturate', $image); 351 } 352 353 /** 354 * Open an image file and return an image object. 355 * 356 * Any changes to the file are not saved until imageapi_image_close() is called. 357 * 358 * @param $file 359 * Path to an image file. 360 * @param $toolkit 361 * An optional, image toolkit name to override the default. 362 * @return 363 * An image object or FALSE if there was a problem loading the file. The 364 * image object has the following properties: 365 * - 'source' - The original file path. 366 * - 'info' - The array of information returned by image_get_info() 367 * - 'toolkit' - The name of the image toolkit requested when the image was 368 * loaded. 369 * Image tookits may add additional properties. The caller is advised not to 370 * monkey about with them. 371 */ 372 function imageapi_image_open($file, $toolkit = FALSE) { 373 if (!$toolkit) { 374 $toolkit = imageapi_default_toolkit(); 375 } 376 if ($toolkit) { 377 $image = new stdClass(); 378 $image->source = $file; 379 $image->info = image_get_info($file); 380 $image->toolkit = $toolkit; 381 if (imageapi_toolkit_invoke('open', $image)) { 382 return $image; 383 } 384 } 385 return FALSE; 386 } 387 388 /** 389 * Close the image and save the changes to a file. 390 * 391 * @param $image 392 * An image object returned by imageapi_image_open(). The object's 'info' 393 * property will be updated if the file is saved successfully. 394 * @param $destination 395 * Destination path where the image should be saved. If it is empty the 396 * original image file will be overwritten. 397 * @return 398 * TRUE or FALSE, based on success. 399 */ 400 function imageapi_image_close($image, $destination = NULL) { 401 if (empty($destination)) { 402 $destination = $image->source; 403 } 404 if ($return = imageapi_toolkit_invoke('close', $image, array($destination))) { 405 // Clear the cached file size and refresh the image information. 406 clearstatcache(); 407 $image->info = image_get_info($destination); 408 409 if (@chmod($destination, 0664)) { 410 return $return; 411 } 412 watchdog('imageapi', 'Could not set permissions on destination file: %file', array('%file' => $destination)); 413 } 414 return FALSE; 415 } 416 417 418 /** 419 * Convert a hex string to its RGBA (Red, Green, Blue, Alpha) integer 420 * components. 421 * 422 * @param $hex 423 * A string specifing an RGB color in the formats: 424 * '#ABC','ABC','#ABCD','ABCD','#AABBCC','AABBCC','#AABBCCDD','AABBCCDD' 425 * @return 426 * An array with four elements for red, green, blue, and alpha. 427 */ 428 function imageapi_hex2rgba($hex) { 429 $hex = ltrim($hex, '#'); 430 if (preg_match('/^[0-9a-f]{3}$/i', $hex)) { 431 // 'FA3' is the same as 'FFAA33' so r=FF, g=AA, b=33 432 $r = str_repeat($hex{0}, 2); 433 $g = str_repeat($hex{1}, 2); 434 $b = str_repeat($hex{2}, 2); 435 $a = '0'; 436 } 437 elseif (preg_match('/^[0-9a-f]{6}$/i', $hex)) { 438 // #FFAA33 or r=FF, g=AA, b=33 439 list($r, $g, $b) = str_split($hex, 2); 440 $a = '0'; 441 } 442 elseif (preg_match('/^[0-9a-f]{8}$/i', $hex)) { 443 // #FFAA33 or r=FF, g=AA, b=33 444 list($r, $g, $b, $a) = str_split($hex, 2); 445 } 446 elseif (preg_match('/^[0-9a-f]{4}$/i', $hex)) { 447 // 'FA37' is the same as 'FFAA3377' so r=FF, g=AA, b=33, a=77 448 $r = str_repeat($hex{0}, 2); 449 $g = str_repeat($hex{1}, 2); 450 $b = str_repeat($hex{2}, 2); 451 $a = str_repeat($hex{3}, 2); 452 } 453 else { 454 //error: invalide hex string, TODO: set form error.. 455 return FALSE; 456 } 457 458 $r = hexdec($r); 459 $g = hexdec($g); 460 $b = hexdec($b); 461 $a = hexdec($a); 462 return array($r, $g, $b, $a); 463 } 464
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 |