imageapi_imagemagick_image_rotate() doesn't update width and height in $image
kaare - February 11, 2009 - 03:03
| Project: | ImageAPI |
| Version: | 6.x-1.3 |
| Component: | Code |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs work |
Jump to:
Description
imageapi_image_rotate() will not report back the resulting width and height after rotation. In the gd toolkit it's an easy fix (patch applied), but due to the parameter pipeline nature of imagemagick toolkit, more care needs to be taken.
For imageapi_imagemagick_image_rotate() I've tried to apply the calculation used in imagerotate.inc, but it doesn't calculate the exact same size as the ones imagemagick produces. Lot of off-by-one errors. Still, I think this is a better approach than not reporting anything. This patch is the first attempt at creating a canvas calculation function for rotation based on this code.
| Attachment | Size |
|---|---|
| gd_rotate_new_size.patch | 382 bytes |
| im_rotate_new_size.patch | 1.7 KB |

#1
Fixed typo in title.
#2
Yeah, I identified the same a while ago.
I didn't come up with the imagemagick fix though.
Hope it works!
#3
I committed the GD portion to HEAD and DRUPAL-6--1 since that was straight forward. The ImageMagick bit I want to look at a bit more.
#4
Here's my overcommented version of the same thing.
Looks like kaare's one would have worked just fine, but for no good reason I ended up doing it myself also. I missed/forgot that there was this patch pending :-/
I'm building a test suite for all our actions, finally having a go at imagemagick, and this issue got in my face again. It is a bug, and I've failed to find a better answer than just doing the maths ourselves.
Turns out the logic I came up with independently is basically the same as the previous patch :-} I guess that's a good sign.
<?php
function imageapi_imagemagick_image_rotate(&$image, $degrees, $bgcolor) {
if (is_int($bgcolor)) {
$bgcolor = '#'. str_pad(dechex($bgcolor), 6, 0);
}
else {
$bgcolor = str_replace('0x', '#', $bgcolor);
}
$image->ops[] = '-background '. escapeshellarg($bgcolor) .' -rotate '. (float) $degrees;
// Need to update the dimensions for later operations in the pipeline
// otherwise (eg) rotate then scale is badly wrong.
$dimensions = imageapi_imagemagick_calculate_rotated_dimensions($image->info['width'], $image->info['height'], $degrees);
$image->info['width'] = $dimensions['width'];
$image->info['height'] = $dimensions['height'];
return TRUE;
}
/**
* Calculate the new dimensions of a rotated image.
*
* Given the dimensions of a box, and an angle, return the dimensions of a new
* containing box.
*
* @return a named array containing values for width and height.
*/
function imageapi_imagemagick_calculate_rotated_dimensions($width, $height, $degrees) {
// There may be several maths short cuts, eg matrices,
// but doing it the long way like this is clear code and geometry.
// Compressing things just made it 'clever' in a bad way.
//
// @see stackoverflow.com/questions/622140/calculate-bounding-box-coordinates-from-a-rotated-rectangle-picture-inside
//
$theta = deg2rad($degrees);
// Set up a box.
$points = array(
array(0, 0),
array($width, 0),
array(0, $height),
array($width, $height),
);
$bounding_box = array(
'left' => 0,
'right' => 0,
'top' => 0,
'bottom' => 0,
);
// Rotate each point in the box
foreach ($points as $p => $point) {
$x = $point[0];
$y = $point[1];
$new_x = ($x)*cos($theta)+($y)*sin($theta);
$new_y = ($x)*sin($theta)+($y)*cos($theta);
// Note the bounds
$bounding_box['left'] = min($bounding_box['left'], $new_x);
$bounding_box['right'] = max($bounding_box['right'], $new_x);
$bounding_box['top'] = min($bounding_box['top'], $new_y);
$bounding_box['bottom'] = max($bounding_box['bottom'], $new_y);
}
// And how big is the new box?
$dimensions = array(
'width' => (int)abs($bounding_box['right'] - $bounding_box['left']),
'height' => (int)abs($bounding_box['bottom'] - $bounding_box['top']),
);
return $dimensions;
}
?>
#5
better title. i'll try to review this this afternoon.