summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/image.inc30
-rw-r--r--modules/simpletest/tests/image.test80
-rw-r--r--modules/simpletest/tests/image_test.module15
-rw-r--r--modules/system/image.gd.inc76
-rw-r--r--modules/system/system.api.php1
5 files changed, 186 insertions, 16 deletions
diff --git a/includes/image.inc b/includes/image.inc
index 6f94810e0..a1e674cc1 100644
--- a/includes/image.inc
+++ b/includes/image.inc
@@ -226,12 +226,11 @@ function image_scale(stdClass $image, $width = NULL, $height = NULL, $upscale =
* The target width, in pixels.
* @param $height
* The target height, in pixels.
- * @param $toolkit
- * An optional override of the default image toolkit.
* @return
* TRUE or FALSE, based on success.
*
* @see image_load()
+ * @see image_gd_resize()
*/
function image_resize(stdClass $image, $width, $height) {
$width = (int) round($width);
@@ -241,6 +240,29 @@ function image_resize(stdClass $image, $width, $height) {
}
/**
+ * Rotate an image by the given number of degrees.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $degrees
+ * The number of (clockwise) degrees to rotate the image.
+ * @param $background
+ * An hexadecimal 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. For images that support
+ * transparency, this will default to transparent. Otherwise it will
+ * be white.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_load()
+ * @see image_gd_rotate()
+ */
+function image_rotate(stdClass $image, $degrees, $background = NULL) {
+ return image_toolkit_invoke('rotate', $image, array($degrees, $background));
+}
+
+/**
* Crop an image to the rectangle specified by the given rectangle.
*
* @param $image
@@ -258,6 +280,7 @@ function image_resize(stdClass $image, $width, $height) {
*
* @see image_load()
* @see image_scale_and_crop()
+ * @see image_gd_crop()
*/
function image_crop(stdClass $image, $x, $y, $width, $height) {
$aspect = $image->info['height'] / $image->info['width'];
@@ -279,6 +302,7 @@ function image_crop(stdClass $image, $x, $y, $width, $height) {
* TRUE or FALSE, based on success.
*
* @see image_load()
+ * @see image_gd_desaturate()
*/
function image_desaturate(stdClass $image) {
return image_toolkit_invoke('desaturate', $image);
@@ -307,6 +331,7 @@ function image_desaturate(stdClass $image) {
* @see image_save()
* @see image_get_info()
* @see image_get_available_toolkits()
+ * @see image_gd_load()
*/
function image_load($file, $toolkit = FALSE) {
if (!$toolkit) {
@@ -337,6 +362,7 @@ function image_load($file, $toolkit = FALSE) {
* TRUE or FALSE, based on success.
*
* @see image_load()
+ * @see image_gd_save()
*/
function image_save(stdClass $image, $destination = NULL) {
if (empty($destination)) {
diff --git a/modules/simpletest/tests/image.test b/modules/simpletest/tests/image.test
index 2348b28e1..4be01c773 100644
--- a/modules/simpletest/tests/image.test
+++ b/modules/simpletest/tests/image.test
@@ -146,6 +146,19 @@ class ImageToolkitTestCase extends DrupalWebTestCase {
}
/**
+ * Test the image_rotate() function.
+ */
+ function testRotate() {
+ $this->assertTrue(image_rotate($this->image, 90, 1), t('Function returned the expected value.'));
+ $this->assertToolkitOperationsCalled(array('rotate'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['rotate'][0][1], 90, t('Degrees were passed correctly'));
+ $this->assertEqual($calls['rotate'][0][2], 1, t('Background color was passed correctly'));
+ }
+
+ /**
* Test the image_crop() function.
*/
function testCrop() {
@@ -193,7 +206,7 @@ class ImageToolkitGdTestCase extends DrupalWebTestCase {
function getInfo() {
return array(
'name' => t('Image GD manipulation tests'),
- 'description' => t('Check that core image manipulations work properly: scale, resize, crop, scale and crop, and desaturate.'),
+ 'description' => t('Check that core image manipulations work properly: scale, resize, rotate, crop, scale and crop, and desaturate.'),
'group' => t('Image API'),
);
}
@@ -304,18 +317,63 @@ class ImageToolkitGdTestCase extends DrupalWebTestCase {
'height' => 8,
'corners' => array_fill(0, 4, $this->black),
),
- 'desaturate' => array(
- 'function' => 'desaturate',
- 'arguments' => array(),
- 'height' => 20,
- 'width' => 40,
- // Grayscale corners are a bit funky. Each of the corners are a shade of
- // gray. The values of these were determined simply by looking at the
- // final image to see what desaturated colors end up being.
- 'corners' => array(array_fill(0, 3, 76) + array(3 => 0), array_fill(0, 3, 149) + array(3 => 0), array_fill(0, 3, 29) + array(3 => 0), array_fill(0, 3, 0) + array(3 => 127)),
- ),
);
+ // Systems using non-bundled GD2 don't have imagerotate. Test if available.
+ if (drupal_function_exists('imagerotate')) {
+ $operations += array(
+ 'rotate_5' => array(
+ 'function' => 'rotate',
+ 'arguments' => array(5, 0xFF00FF), // Fuchsia background.
+ 'width' => 42,
+ 'height' => 24,
+ 'corners' => array_fill(0, 4, $this->fuchsia),
+ ),
+ 'rotate_90' => array(
+ 'function' => 'rotate',
+ 'arguments' => array(90, 0xFF00FF), // Fuchsia background.
+ 'width' => 20,
+ 'height' => 40,
+ 'corners' => array($this->fuchsia, $this->red, $this->green, $this->blue),
+ ),
+ 'rotate_transparent_5' => array(
+ 'function' => 'rotate',
+ 'arguments' => array(5),
+ 'width' => 42,
+ 'height' => 24,
+ 'corners' => array_fill(0, 4, $this->transparent),
+ ),
+ 'rotate_transparent_90' => array(
+ 'function' => 'rotate',
+ 'arguments' => array(90),
+ 'width' => 20,
+ 'height' => 40,
+ 'corners' => array($this->transparent, $this->red, $this->green, $this->blue),
+ ),
+ );
+ }
+
+ // Systems using non-bundled GD2 don't have imagefilter. Test if available.
+ if (drupal_function_exists('imagefilter')) {
+ $operations += array(
+ 'desaturate' => array(
+ 'function' => 'desaturate',
+ 'arguments' => array(),
+ 'height' => 20,
+ 'width' => 40,
+ // Grayscale corners are a bit funky. Each of the corners are a shade of
+ // gray. The values of these were determined simply by looking at the
+ // final image to see what desaturated colors end up being.
+ 'corners' => array(
+ array_fill(0, 3, 76) + array(3 => 0),
+ array_fill(0, 3, 149) + array(3 => 0),
+ array_fill(0, 3, 29) + array(3 => 0),
+ array_fill(0, 3, 0) + array(3 => 127)
+ ),
+ ),
+ );
+ }
+
foreach ($files as $file) {
foreach ($operations as $op => $values) {
// Load up a fresh image.
diff --git a/modules/simpletest/tests/image_test.module b/modules/simpletest/tests/image_test.module
index 07f59461d..ed2cd320f 100644
--- a/modules/simpletest/tests/image_test.module
+++ b/modules/simpletest/tests/image_test.module
@@ -34,6 +34,7 @@ function image_test_reset() {
'save' => array(),
'settings' => array(),
'resize' => array(),
+ 'rotate' => array(),
'crop' => array(),
'desaturate' => array(),
);
@@ -46,8 +47,8 @@ function image_test_reset() {
*
* @return
* An array keyed by operation name ('load', 'save', 'settings', 'resize',
- * 'crop', 'desaturate') with values being arrays of parameters passed to
- * each call.
+ * 'rotate', 'crop', 'desaturate') with values being arrays of parameters
+ * passed to each call.
*/
function image_test_get_all_calls() {
return variable_get('image_test_results', array());
@@ -58,7 +59,7 @@ function image_test_get_all_calls() {
*
* @param $op
* One of the image toolkit operations: 'load', 'save', 'settings', 'resize',
- * 'crop', 'desaturate'.
+ * 'rotate', 'crop', 'desaturate'.
* @param $args
* Values passed to hook.
* @see image_test_get_all_calls()
@@ -113,6 +114,14 @@ function image_test_resize(stdClass $image, $width, $height) {
}
/**
+ * Image tookit's rotate operation.
+ */
+function image_test_rotate(stdClass $image, $degrees, $background = NULL) {
+ _image_test_log_call('rotate', array($image, $degrees, $background));
+ return TRUE;
+}
+
+/**
* Image tookit's desaturate operation.
*/
function image_test_desaturate(stdClass $image) {
diff --git a/modules/system/image.gd.inc b/modules/system/image.gd.inc
index 2ba31bbc6..a67ecf470 100644
--- a/modules/system/image.gd.inc
+++ b/modules/system/image.gd.inc
@@ -98,6 +98,76 @@ function image_gd_resize(stdClass $image, $width, $height) {
}
/**
+ * Rotate an image the given number of degrees.
+ *
+ * @param $image
+ * An image object. The $image->resource, $image->info['width'], and
+ * $image->info['height'] values will be modified by this call.
+ * @param $degrees
+ * The number of (clockwise) degrees to rotate the image.
+ * @param $background
+ * An hexadecimal 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. For images that support
+ * transparency, this will default to transparent. Otherwise it will
+ * be white.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_rotate()
+ */
+function image_gd_rotate(stdClass $image, $degrees, $background = NULL) {
+ // PHP installations using non-bundled GD do not have imagerotate.
+ if (!drupal_function_exists('imagerotate')) {
+ watchdog('image', 'The image %file could not be rotated because the imagerotate() function is not available in this PHP installation.', array('%file' => $image->source));
+ return FALSE;
+ }
+
+ $width = $image->info['width'];
+ $height = $image->info['height'];
+
+ // Convert the hexadecimal background value to a color index value.
+ if (isset($background)) {
+ $rgb = array();
+ for ($i = 16; $i >= 0; $i -= 8) {
+ $rgb[] = (($background >> $i) & 0xFF);
+ }
+ $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0);
+ }
+ // Set the background color as transparent if $background is NULL.
+ else {
+ // Get the current transparent color.
+ $background = imagecolortransparent($image->resource);
+
+ // If no transparent colors, use white.
+ if ($background == 0) {
+ $background = imagecolorallocatealpha($image->resource, 255, 255, 255, 0);
+ }
+ }
+
+ // Images are assigned a new color pallete when rotating, removing any
+ // transparency flags. For GIF images, keep a record of the transparent color.
+ if ($image->info['extension'] == 'gif') {
+ $transparent_index = imagecolortransparent($image->resource);
+ if ($transparent_index != 0) {
+ $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index);
+ }
+ }
+
+ $image->resource = imagerotate($image->resource, 360 - $degrees, $background);
+
+ // GIFs need to reassign the transparent color after performing the rotate.
+ if (isset($transparent_gif_color)) {
+ $background = imagecolorexactalpha($image->resource, $transparent_gif_color['red'], $transparent_gif_color['green'], $transparent_gif_color['blue'], $transparent_gif_color['alpha']);
+ imagecolortransparent($image->resource, $background);
+ }
+
+ $image->info['width'] = imagesx($image->resource);
+ $image->info['height'] = imagesy($image->resource);
+ return TRUE;
+}
+
+/**
* Crop an image using the GD toolkit.
*
* @param $image
@@ -144,6 +214,12 @@ function image_gd_crop(stdClass $image, $x, $y, $width, $height) {
* @see image_desaturate()
*/
function image_gd_desaturate(stdClass $image) {
+ // PHP installations using non-bundled GD do not have imagefilter.
+ if (!drupal_function_exists('imagefilter')) {
+ watchdog('image', 'The image %file could not be rotated because the imagefilter() function is not available in this PHP installation.', array('%file' => $image->source));
+ return FALSE;
+ }
+
return imagefilter($image->resource, IMG_FILTER_GRAYSCALE);
}
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index 7e77e7dcd..ab0e5eb07 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -377,6 +377,7 @@ function hook_init() {
* - 'save': Required. See image_gd_save() for usage.
* - 'settings': Optional. See image_gd_settings() for usage.
* - 'resize': Optional. See image_gd_resize() for usage.
+ * - 'rotate': Optional. See image_gd_rotate() for usage.
* - 'crop': Optional. See image_gd_crop() for usage.
* - 'desaturate': Optional. See image_gd_desaturate() for usage.
*