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
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.

AttachmentSize
gd_rotate_new_size.patch382 bytes
im_rotate_new_size.patch1.7 KB

#1

kaare - February 11, 2009 - 03:04
Title:rotate() don't update width and height in $image» rotate() doesn't update width and height in $image

Fixed typo in title.

#2

dman - February 12, 2009 - 23:54

Yeah, I identified the same a while ago.
I didn't come up with the imagemagick fix though.
Hope it works!

#3

drewish - February 13, 2009 - 02:30

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

dman - April 12, 2009 - 15:03

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

drewish - April 13, 2009 - 19:12
Title:rotate() doesn't update width and height in $image» imageapi_imagemagick_image_rotate() doesn't update width and height in $image

better title. i'll try to review this this afternoon.

 
 

Drupal is a registered trademark of Dries Buytaert.