Preserve image's aspect ratio when width AND height defined

mrb@drupal.org - February 25, 2009 - 08:43
Project:Embedded Media Field
Version:6.x-1.x-dev
Component:Embedded Image Field
Category:bug report
Priority:normal
Assigned:Unassigned
Status:active
Description

Currently there is no way to fit an image in a specified size, and keep its original aspect ratio. eg the width of our main column is 510 pixels, so I want to set the 'Full size' with and height to be 510.

But the current code then forces all images to display at exactly 510x510 pixels, distorting any images that weren't originally square.

Instead I'd like the image to be scaled to fit within the specified size, but keeping its original aspect ratio.

#1

mrb@drupal.org - February 25, 2009 - 08:50
Status:active» needs review
AttachmentSize
emfield-383274.patch 1.76 KB

#2

mrb@drupal.org - February 25, 2009 - 10:55
Status:needs review» active

Please ignore the previous patch, it doesn't work. Here's the function I've changed. The problem is that the call to getimagesize is returning false, though the url seems to be right, eg
"http://farm4.static.flickr.com/3297/3236587333_3f71cdf1e9_o.jpg"

Any ideas why getimagesize doesn't work, or ideas of other ways to find the image's dimensions?

<?php
function theme_emimage_image($field, $item, $formatter, $node, $code, $width, $height, $title = '', $link = NULL) {
 
$url = module_invoke('emfield', 'include_invoke', 'emimage', $item['provider'], 'image_url', $code, $width, $height, $formatter, $field, $item, $node);
 
$attributes = array();
 
 
// Set the image's width or height attribute for the browser, and let the browser scale
  // the image, preserving its original aspect ratio.
  // There are three options allowed in the admin settings:
  // 1. width == 0. Display image at specified height,
  //    with width scaled according to original aspect ratio.
  // 2. height == 0. Display image at specified width,
  //    with height scaled according to original aspect ratio.
  // 3. Both width and height are non-zero. Change it to display the image
  //    at the largest size that fits within the specified height & width,
  //    and preserves the original aspect ratio.

 
if ($width == 0) {
   
$attributes['height'] = $height;
  }
  elseif (
$height == 0) {
   
$attributes['width'] = $width;
  }
  else {
   
// Find out the size of the actual image file, and scale accordingly
   
list($actual_width, $actual_height, $type, $image_attributes) = getimagesize($url) ;
    if ( (
$actual_width >0 ) && ($actual_height >0) ) {
     
$scale_width = $actual_width / $width ;
     
$scale_height = $actual_height / $height ;
      if (
$scale_width < $scale_height) {
       
$attributes['width'] = $width;
      }
      else {
       
$attributes['height'] = $height;
      }
    }
    else {
     
// getimagesize didn't work, so set both. Safer, but will lose aspect ratio.
     
$attributes['width'] = $width;
     
$attributes['height'] = $height;     
    }
  }

  if (
$item['class']){
     
$attributes['class'] = $item['class'];
  }
  else if (
$item['provider']) {
     
$attributes['class'] = $item['provider'];
  }
 
$output = theme('image', $url, $title, $title, $attributes, false);
 
  if (
$link) {
   
$output = l($output, $link, array('html' => true));
  }
  return
$output;
}
?>

#3

mrb@drupal.org - February 26, 2009 - 04:06

The following code works (it uses curl instead of getimagesize), but fetching the image every time it is displayed is a bit crazy. Any suggestions on the right way to approach this?

I'm thinking to have theme_emimage_image just look in $item for width and height entries, and have emfield_PROVIDER_data responsible for setting those values when the node is initially created. It looks like picasa.inc already does this. Does that sound right?

<?php
function theme_emimage_image($field, $item, $formatter, $node, $code, $width, $height, $title = '', $link = NULL) {
 
$url = module_invoke('emfield', 'include_invoke', 'emimage', $item['provider'], 'image_url', $code, $width, $height, $formatter, $field, $item, $node);
 
$attributes = array();
 
 
// Set the image's width or height attribute for the browser, and let the browser scale
  // the image, preserving its original aspect ratio.
  // There are three options allowed in the admin settings:
  // 1. width == 0. Display image at specified height,
  //    with width scaled according to original aspect ratio.
  // 2. height == 0. Display image at specified width,
  //    with height scaled according to original aspect ratio.
  // 3. Both width and height are non-zero. Change it to display the image
  //    at the largest size that fits within the specified height & width,
  //    and preserves the original aspect ratio.

 
if ($width == 0) {
   
$attributes['height'] = $height;
  }
  elseif (
$height == 0) {
   
$attributes['width'] = $width;
  }
  else {
   
// Find out the size of the actual image file, and scale accordingly
   
$actual_width = false ;
   
$actual_height = false ;

   
// THE 'getimagesize' CODE HAS NOT BEEN TESTED YET,
// THOUGH THE CURL CODE BELOW IS WORKING OK   

   
if (ini_get('allow_url_fopen')) {
     
// It is safe to call getimagesize on a remote file
     
$size = @getimagesize($url) ;
      if (
$size !== false) {
       
$actual_width = $size[0] ;
       
$actual_height = $size[1] ;
      }
    }
    elseif (
function_exists('curl_exec')) {
     
// Many sites don't have 'allow_url_fopen' enabled, but if curl is
      // enabled we can use that instead
     
$ch = curl_init();    // initialize curl handle
     
curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
     
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
     
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable
     
curl_setopt($ch, CURLOPT_TIMEOUT, 3); // times out after 4s
     
$curl_file = curl_exec($ch); // run the whole process
     
curl_close($ch); 
     
$curl_image = @imagecreatefromstring($curl_file);
      if (
$curl_image !== false) {
       
$actual_width = @imagesx($curl_image);
       
$actual_height = @imagesy($curl_image);
      }
      unset(
$curl_file, $curl_image);
    }
   
    if (
$actual_width && $actual_height ) {
     
$scale_width = $actual_width / $width ;
     
$scale_height = $actual_height / $height ;
      if (
$scale_width > $scale_height) {
       
$attributes['width'] = $width;
      }
      else {
       
$attributes['height'] = $height;
      }
    }
    else {
     
// We don't know the size of the image, so just make it fill the space available.
      // It will probably be stretched in one direction, making it look odd.
     
$attributes['width'] = $width;
     
$attributes['height'] = $height;     
    }
  }

  if (
$item['class']){
     
$attributes['class'] = $item['class'];
  }
  else if (
$item['provider']) {
     
$attributes['class'] = $item['provider'];
  }
 
$output = theme('image', $url, $title, $title, $attributes, false);
 
  if (
$link) {
   
$output = l($output, $link, array('html' => true));
  }
  return
$output;
}
?>

#4

smooshy - March 2, 2009 - 18:37

subscribe

#5

mrb@drupal.org - March 19, 2009 - 06:28
Assigned to:Anonymous» mrb@drupal.org
Status:active» needs review

This works for me - please can you let me know if it's ok for you too.

The first patch is to theme_emimage_image in emimage.theme.inc. This version looks to see if emfield_PROVIDER_data had set values for the image's height & width, and if yes it scales the image to fit within the specified size, while preserving its aspect ratio. If they are not set, it behaves like the current beta1 version.

The second patch is to flickr.inc, so that it sets the height & width required above.

If you have an existing embedded flickr image, you'll need to edit & save it (no need to make any changes) before you see the effects of these patches.

AttachmentSize
emfield-383274-5-emimage.theme_.inc_.patch 2.11 KB
emfield-383274-5-flickr.inc_.patch 882 bytes

#6

mrb@drupal.org - March 20, 2009 - 07:53
Assigned to:mrb@drupal.org» Anonymous

#7

stormsweeper - March 27, 2009 - 14:36

getimagesize will fail if your PHP doesn't have zlib compiled in. If you enable NOTICE logging you should see the exact message. To confirm, go to your Drupal status page, and then click on the PHP version and look at compile flags.

#8

jcmarco - April 7, 2009 - 12:21

#9

Alex UA - April 19, 2009 - 21:43
Status:needs review» closed

Should now be fixed. See the issue linked to in #8

#10

mrb@drupal.org - April 24, 2009 - 06:07
Title:Preserve image's aspect ratio when scaling» Preserve image's aspect ratio when width AND height defined
Status:closed» needs review

Hi, moving this back to active, as the problem & patch I'm describing are different from that in #8. I'll try and explain it better.

I want to use Views to build a gallery of emfield images, and have it display as a grid of images, just like any other gallery you see on the web.

I set the dimensions of the thumbnail to be 150x150. See 150x150-org.jpg. That shows a grid, but all images are stretched to fit the 150x150 square shape, so they are distorted.

I read that setting one dimension to 0 preserves the aspect ratio, so I tried dimensions of 150x0. See 150x0-org.jpg. Now the images looks ok, but the gallery looks wrong. Portrait images always appear much larger than landscape images, not how a gallery usually looks.

So, the patch in #5 preserves the aspect ratio, AND fits the image within the specified dimensions. After installing the patch, and setting the dimensions to 150x150 we get 150x150-patch.jpg, which I think looks better.

AttachmentSize
150x150-org.jpg 119.63 KB
150x0-org.jpg 141 KB
150x150-patch.jpg 95.14 KB

#11

Alex UA - May 9, 2009 - 21:16
Status:needs review» fixed

I'm comitting this right now. Thanks for the fix!

#12

jcmarco - May 10, 2009 - 21:48
Status:fixed» needs review

I found some typos when last patches were committed into the module, it seems that there are some lost lines.

Also found problems with Flickr when the $item['data'] is serialized so the "square" escalation was not possible.

Once fixed the lost lines in the emimage.theme.inc and fixed the issue with the serialized data, the patch worked genially.
Allowing working in both ways with an automatic size adaptation (using 0 in some dimension) or defining a "squared" max dimensions.

I couldn't test it with other image providers than Flickr.

AttachmentSize
emimage.theme_.inc_.patch 1.09 KB

#13

Alex UA - May 11, 2009 - 01:17

Very odd. Yesterday I had this working, without your most recent patch. I just added the patch, and now everything is getting stretched again. Is there anything else missing?

#14

smazsyr - May 18, 2009 - 02:24

Using the dev version, which I think has the latest patches, I receive the following error upon saving, and on displaying a node with an embedded image from Flickr:

warning: Division by zero in /home/thenew/public_html/sites/all/modules/emfield/contrib/emimage/emimage.theme.inc on line 15.

#15

aaron - May 29, 2009 - 01:19

Fixed the division by zero error. Not sure if there's anything else here that needs attention?

#16

aaron - May 29, 2009 - 02:01
Status:needs review» fixed

OK, Fixed the thing entirely now. Should work fine.

#17

System Message - June 12, 2009 - 02:10
Status:fixed» closed

Automatically closed -- issue fixed for 2 weeks with no activity.

#18

srobert72 - August 27, 2009 - 09:25
Version:6.x-1.0-beta1» 6.x-1.x-dev
Status:closed» active

I'm using Emfield 6.x-1.x-dev (2009-Aug-26)
I'm facing issue described in #10 (http://drupal.org/node/383274#comment-1514208)
All is like if patch doesn't operate.

I'd want to set width and height so that depending on image orientation (lanscape or portrait) width and height both never exceed certain length. All that respecting aspect ration.
By example I set 150x150 so that :
original image 400x200 is resized 150x75
original image 200x400 is resized 75x150

For me with Emfield 6.x-1.x-dev (2009-Aug-26) it doesn't appear like it would need as mentionned on attached picture : http://drupal.org/files/issues/150x150-patch.jpg

Is the patch commited in dev release ?

#19

cloneofsnake - October 3, 2009 - 05:02

Having the same problem, and this seems like a trivial thing. The settings should be:

Max Height:
Max Width:
Keep Aspect Ration (checkbox)

Checkbox should default to checked.

#20

Sylvain Lasnier - October 6, 2009 - 11:53

Hi,
I have same problem with other dimension. 1024px × 682px image is scaling to 500px × 800px.

#21

Sylvain Lasnier - October 6, 2009 - 11:55

"keep aspect ratio" or "crop" will be perfect.

#22

srobert72 - November 26, 2009 - 19:58

Subscribing again

 
 

Drupal is a registered trademark of Dries Buytaert.