Specify a background color for crops since they can add area to the canvas. From: <> http://drupal.org/node/437702 --- includes/image.inc | 30 +++++-- modules/simpletest/tests/image.test | 31 ++++++- modules/simpletest/tests/image_test.module | 8 +- modules/system/image.gd.inc | 122 +++++++++++++++++----------- 4 files changed, 122 insertions(+), 69 deletions(-) diff --git includes/image.inc includes/image.inc index 4309ac9..45bff2c 100644 --- includes/image.inc +++ includes/image.inc @@ -250,19 +250,22 @@ function image_resize(stdClass $image, $width, $height) { * @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. + * An optional, 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. If the format + * supports transparency and the $transparent parameter is TRUE this value + * will be ignored. + * @param $transparent + * Boolean indicating that formats that support transparency (e.g. PNG and + * GIF) should ignore the background color and use a transparent background. * @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)); +function image_rotate(stdClass $image, $degrees, $background = 0xffffff, $transparent = TRUE) { + return image_toolkit_invoke('rotate', $image, array($degrees, $background, $transparent)); } /** @@ -278,6 +281,15 @@ function image_rotate(stdClass $image, $degrees, $background = NULL) { * The target width, in pixels. * @param $height * The target height, in pixels. + * @param $background + * An optional, hexadecimal integer specifying the background color to use + * for areas added during crops that add area to the image. E.g. 0x000000 for + * black, 0xff00ff for magenta, and 0xffffff for white. If the format + * supports transparency and the $transparent parameter is TRUE this value + * will be ignored. + * @param $transparent + * Boolean indicating that formats that support transparency (e.g. PNG and + * GIF) should ignore the background color and use a transparent background. * @return * TRUE or FALSE, based on success. * @@ -285,7 +297,7 @@ function image_rotate(stdClass $image, $degrees, $background = NULL) { * @see image_scale_and_crop() * @see image_gd_crop() */ -function image_crop(stdClass $image, $x, $y, $width, $height) { +function image_crop(stdClass $image, $x, $y, $width, $height, $background = 0xffffff, $transparent = TRUE) { $aspect = $image->info['height'] / $image->info['width']; if (empty($height)) $height = $width / $aspect; if (empty($width)) $width = $height * $aspect; @@ -293,7 +305,7 @@ function image_crop(stdClass $image, $x, $y, $width, $height) { $width = (int) round($width); $height = (int) round($height); - return image_toolkit_invoke('crop', $image, array($x, $y, $width, $height)); + return image_toolkit_invoke('crop', $image, array($x, $y, $width, $height, $background, $transparent)); } /** diff --git modules/simpletest/tests/image.test modules/simpletest/tests/image.test index cd2423b..2367884 100644 --- modules/simpletest/tests/image.test +++ modules/simpletest/tests/image.test @@ -149,20 +149,21 @@ 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->assertTrue(image_rotate($this->image, 90, 0xabcdef, TRUE), 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')); + $this->assertEqual($calls['rotate'][0][2], 0xabcdef, t('Background color was passed correctly')); + $this->assertEqual($calls['rotate'][0][3], TRUE, t('Transparent was passed correctly')); } /** * Test the image_crop() function. */ function testCrop() { - $this->assertTrue(image_crop($this->image, 1, 2, 3, 4), t('Function returned the expected value.')); + $this->assertTrue(image_crop($this->image, 1, 2, 3, 4, 0xabcdef, TRUE), t('Function returned the expected value.')); $this->assertToolkitOperationsCalled(array('crop')); // Check the parameters. @@ -171,6 +172,8 @@ class ImageToolkitTestCase extends DrupalWebTestCase { $this->assertEqual($calls['crop'][0][2], 2, t('Y was passed correctly')); $this->assertEqual($calls['crop'][0][3], 3, t('Width was passed correctly')); $this->assertEqual($calls['crop'][0][4], 4, t('Height was passed correctly')); + $this->assertEqual($calls['crop'][0][5], 0xabcdef, t('Background was passed correctly')); + $this->assertEqual($calls['crop'][0][6], TRUE, t('Transparent was passed correctly')); } /** @@ -310,6 +313,20 @@ class ImageToolkitGdTestCase extends DrupalWebTestCase { 'height' => 12, 'corners' => array_fill(0, 4, $this->white), ), + 'upcrop_colored' => array( + 'function' => 'crop', + 'arguments' => array(0, 0, 80, 40, 0xFF00FF, FALSE), + 'width' => 80, + 'height' => 40, + 'corners' => array_fill(0, 4, $this->fuchsia), + ), + 'upcrop_transparent' => array( + 'function' => 'crop', + 'arguments' => array(0, 0, 80, 40, 0xFF00FF, TRUE), + 'width' => 80, + 'height' => 40, + 'corners' => array_fill(0, 4, $this->fuchsia), + ), 'scale_and_crop' => array( 'function' => 'scale_and_crop', 'arguments' => array(10, 8), @@ -324,28 +341,28 @@ class ImageToolkitGdTestCase extends DrupalWebTestCase { $operations += array( 'rotate_5' => array( 'function' => 'rotate', - 'arguments' => array(5, 0xFF00FF), // Fuchsia background. + 'arguments' => array(5, 0xFF00FF, FALSE), // Fuchsia background. 'width' => 42, 'height' => 24, 'corners' => array_fill(0, 4, $this->fuchsia), ), 'rotate_90' => array( 'function' => 'rotate', - 'arguments' => array(90, 0xFF00FF), // Fuchsia background. + 'arguments' => array(90, 0xFF00FF, FALSE), // 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), + 'arguments' => array(5, 0xffffff, TRUE), 'width' => 42, 'height' => 24, 'corners' => array_fill(0, 4, $this->transparent), ), 'rotate_transparent_90' => array( 'function' => 'rotate', - 'arguments' => array(90), + 'arguments' => array(90, 0xffffff, TRUE), 'width' => 20, 'height' => 40, 'corners' => array($this->transparent, $this->red, $this->green, $this->blue), diff --git modules/simpletest/tests/image_test.module modules/simpletest/tests/image_test.module index 86c0c64..23b2d9f 100644 --- modules/simpletest/tests/image_test.module +++ modules/simpletest/tests/image_test.module @@ -100,8 +100,8 @@ function image_test_save(stdClass $image, $destination) { /** * Image tookit's crop operation. */ -function image_test_crop(stdClass $image, $x, $y, $width, $height) { - _image_test_log_call('crop', array($image, $x, $y, $width, $height)); +function image_test_crop(stdClass $image, $x, $y, $width, $height, $background, $transparent) { + _image_test_log_call('crop', array($image, $x, $y, $width, $height, $background, $transparent)); return TRUE; } @@ -116,8 +116,8 @@ 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)); +function image_test_rotate(stdClass $image, $degrees, $background, $transparent) { + _image_test_log_call('rotate', array($image, $degrees, $background, $transparent)); return TRUE; } diff --git modules/system/image.gd.inc modules/system/image.gd.inc index d009caf..cc5e6c8 100644 --- modules/system/image.gd.inc +++ modules/system/image.gd.inc @@ -106,17 +106,20 @@ function image_gd_resize(stdClass $image, $width, $height) { * @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. + * An optional, 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. If the format + * supports transparency and the $transparent parameter is TRUE this value + * will be ignored. + * @param $transparent + * Boolean indicating that formats that support transparency (e.g. PNG and + * GIF) should ignore the background color and use a transparent background. * @return * TRUE or FALSE, based on success. * * @see image_rotate() */ -function image_gd_rotate(stdClass $image, $degrees, $background = NULL) { +function image_gd_rotate(stdClass $image, $degrees, $background = 0xffffff, $transparent = TRUE) { // 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)); @@ -127,38 +130,31 @@ function image_gd_rotate(stdClass $image, $degrees, $background = NULL) { $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); + $rgb = array(); + for ($i = 16; $i >= 0; $i -= 8) { + $rgb[] = (($background >> $i) & 0xFF); } - // 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); + // If the image has a transparent color and that's used + $transparent_index = imagecolortransparent($image->resource); + if ($transparent && $transparent_index != 0) { + // GIFs need to reassign the transparent color after performing the rotate + // so make note of the current, transparent RGB value. + if ($image->info['extension'] == 'gif') { + $gif_transparent_rgb = imagecolorsforindex($image->resource, $transparent_index); } + $background = $transparent_index; } - - // 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); - } + else { + $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0); } + // Rotate it. $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']); + // Update the GIFs transparent color. + if (isset($gif_transparent_rgb)) { + $background = imagecolorexactalpha($image->resource, $gif_transparent_rgb['red'], $gif_transparent_rgb['green'], $gif_transparent_rgb['blue'], $gif_transparent_rgb['alpha']); imagecolortransparent($image->resource, $background); } @@ -181,15 +177,24 @@ function image_gd_rotate(stdClass $image, $degrees, $background = NULL) { * The width of the cropped area, in pixels. * @param $height * The height of the cropped area, in pixels. + * @param $background + * An optional, hexadecimal integer specifying the background color to use + * for areas added during crops that add area to the image. E.g. 0x000000 for + * black, 0xff00ff for magenta, and 0xffffff for white. If the format + * supports transparency and the $transparent parameter is TRUE this value + * will be ignored. + * @param $transparent + * Boolean indicating that formats that support transparency (e.g. PNG and + * GIF) should ignore the background color and use a transparent background. * @return * TRUE or FALSE, based on success. * * @see image_crop() */ -function image_gd_crop(stdClass $image, $x, $y, $width, $height) { - $res = image_gd_create_tmp($image, $width, $height); +function image_gd_crop(stdClass $image, $x, $y, $width, $height, $background = 0xffffff, $transparent = TRUE) { + $res = image_gd_create_tmp($image, $width, $height, $background, $transparent); - if (!imagecopyresampled($res, $image->resource, 0, 0, $x, $y, $width, $height, $width, $height)) { + if (!imagecopy($res, $image->resource, 0, 0, $x, $y, $width, $height)) { return FALSE; } @@ -284,37 +289,56 @@ function image_gd_save(stdClass $image, $destination) { * @return * A GD image handle. */ -function image_gd_create_tmp(stdClass $image, $width, $height) { +function image_gd_create_tmp(stdClass $image, $width, $height, $background = 0xffffff, $transparency = TRUE) { $res = imagecreatetruecolor($width, $height); - if ($image->info['extension'] == 'gif') { - // Grab transparent color index from image resource. - $transparent = imagecolortransparent($image->resource); - - if ($transparent >= 0) { - // The original must have a transparent color, allocate to the new image. - $transparent_color = imagecolorsforindex($image->resource, $transparent); - $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); + // Convert the hexadecimal background value to a color index value. + $rgb = array(); + for ($i = 16; $i >= 0; $i -= 8) { + $rgb[] = (($background >> $i) & 0xFF); + } - // Flood with our new transparent color. - imagefill($res, 0, 0, $transparent); - imagecolortransparent($res, $transparent); +dsm('transparency ' . $transparent); + if ($transparent && $image->info['extension'] == 'gif') { +dsm('making a transparent gif'); + // Check if the GIF has an existing transparent color. + $transparent_index = imagecolortransparent($image->resource); +dsm('$transparent_index');dsm($transparent_index); + if ($transparent_index >= 0) { +# $gif_transparent_rgb = imagecolorsforindex($image->resource, $transparent_index); +#dsm('$gif_transparent_rgb:'); dsm($gif_transparent_rgb); +# $background = imagecolorallocate($res, $gif_transparent_rgb['red'], $gif_transparent_rgb['green'], $gif_transparent_rgb['blue']); + $background = $transparent_index; + } + else { + $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 127); } +dsm($background); + // Flood with our new color then mark it as transparent. + imagefill($res, 0, 0, $background); +# imagefilledrectangle($res, 0, 0, $width, $height, $background); + imagecolortransparent($res, $background); } - elseif ($image->info['extension'] == 'png') { + elseif ($transparent && $image->info['extension'] == 'png') { +dsm('making a transparent png'); imagealphablending($res, FALSE); - $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127); - imagefill($res, 0, 0, $transparency); + $background = imagecolorallocatealpha($res, 0, 0, 0, 127); + imagefill($res, 0, 0, $background); +# imagefilledrectangle($res, 0, 0, $width, $height, $background); imagealphablending($res, TRUE); imagesavealpha($res, TRUE); } else { - imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255)); +dsm('making solid bg'); + $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0); + imagefill($res, 0, 0, $background); +# imagefilledrectangle($res, 0, 0, $width, $height, $background); } return $res; } + /** * @} End of "ingroup image". */