Not sure where this feature request really belongs, as this is quite a basic one - similar to what's described in #967198: Tutorial: How to achieve "Zoom to fill" ImageCache action as known from video players. but for the 7.x-1.0 branch.
At first, I quickly achieved this using a small custom module (which I called 'image_extra_styles') - but I thought It could be useful to share here since I almost always use imagecache_actions anyways, so maybe it could live in there too.
Here's this (simple) module code :


/**
 * @file
 * Extra image custom styles
 */


/**
 * Implement hook_image_effect_info()
 */
function image_extra_styles_image_effect_info() {
  $effects = array(
    'scale_match_long_sides' => array(
      'label' => t( 'Scale while switching width and height to match long sides' ),
      'help' => t( 'Inspired by the excellent FastStone Photo Resizer - operates like the "normal" scaling (maintain the aspect-ratio of the original image & if only a single dimension is specified, the other dimension will be calculated), but if the image is portrait and this style\'s width is bigger than its height (set for landscape images), the scaling will use its height for the image width (so that no dimension ends up being too small or too big).' ),
      'effect callback' => 'image_scale_match_long_sides_effect',
      'dimensions callback' => 'image_scale_match_long_sides_dimensions',
      'form callback' => 'image_scale_form',
      'summary theme' => 'image_scale_summary',
    ),
  );
  return $effects;
}


/**
 * Image effect callback; Scale an image resource while switching width and height to match long sides.
 *
 * @param $image
 *   An image object returned by image_load().
 * @param $data
 *   An array of attributes to use when performing the scale effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *   - "upscale": A boolean indicating that the image should be upscaled if the
 *     dimensions are larger than the original image.
 *
 * @return
 *   TRUE on success. FALSE on failure to scale image.
 *
 * @see image_scale()
 */
function image_scale_match_long_sides_effect(&$image, $data) {
  // Set sane default values.
  $data += array(
    'width' => NULL,
    'height' => NULL,
    'upscale' => FALSE,
  );
  
  // Switch width and height to match long sides if needed
  // (that is : when processing a portrait image when requested scaling is landscape)
  _image_extra_styles_auto_switch_dimesions(array('width' => $image->info['width'], 'height' => $image->info['height']), $data);
  
  if (!image_scale($image, $data['width'], $data['height'], $data['upscale'])) {
    watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
    return FALSE;
  }
  
  return TRUE;
}


/**
 * Image dimensions callback; Scale while switching width and height to match long sides.
 *
 * @param $dimensions
 *   Dimensions to be modified - an array with components width and height, in
 *   pixels.
 * @param $data
 *   An array of attributes to use when performing the scale effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *   - "upscale": A boolean indicating that the image should be upscaled if the
 *     dimensions are larger than the original image.
 */
function image_scale_match_long_sides_dimensions(array &$dimensions, array $data) {
  if ($dimensions['width'] && $dimensions['height']) {
    // Before scaling, switch width and height to match long sides if needed
    _image_extra_styles_auto_switch_dimesions($dimensions, $data);
    image_dimensions_scale($dimensions, $data['width'], $data['height'], $data['upscale']);
  }
}


/**
 * Helper function to automatically switch width and height to match long sides if needed,
 * when processing a portrait image when requested scaling is landscape.
 *
 * @param $dimensions
 *   Dimensions to be modified - an array with components width and height, in
 *   pixels.
 * @param $data
 *   An array of attributes to use when performing the scale effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *   - "upscale": A boolean indicating that the image should be upscaled if the
 *     dimensions are larger than the original image.
 */
function _image_extra_styles_auto_switch_dimesions(array $dimensions, array &$data) {
  if ($dimensions['width'] && $dimensions['height']) {
    $image_is_portrait = false;
    if ($dimensions['width'] < $dimensions['height']) {
      $image_is_portrait = true;
    }
    if ($image_is_portrait && $data['width'] > $data['height']) {
      $data['old_width'] = $data['width'];
      $data['old_height'] = $data['height'];
      $data['height'] = $data['old_width'];
      $data['width'] = $data['old_height'];
    }
  }
}


Comments

fietserwin’s picture

Looks like "scale and crop" from the core effects? If not can you post some examples and/or a more exhaustive description?

paulmicha’s picture

Nope : it's not cropping anything... It's just like the "normal" scaling (maintain the aspect-ratio of the original image), but if the image is portrait and the style's width is bigger than its height (i.e. set for landscape images), the scaling will use its height for the image width (so that no dimension ends up being too small - think portrait or landscape panoramic images).

fietserwin’s picture

Forgive me my lack of imagination, but I still don't get it. Can you give some example calculations?

I arrive at something like:
effect parameters: 600 x 400
image in: 1200x1200 => image out: 400x400
image in: 1200x800 => image out: 600x400
image in: 800x1200 => image out: 400x600
image in: 1200x400 => image out: 600x133
image in: 400x1200 => image out: 400x1200

fietserwin’s picture

Version: 7.x-1.0 » 7.x-1.x-dev

I think I got it:
Instead of defining maximum values for the width and height, you want to define maximum values for the long and short side. This description seems to describe the examples in the previous comment, but now it is clear to me...

I use this effect often when I want to webify a set of photo's (i.e. reduce them in size to shorten download time) and I am not particularly interested in fitting them into a given space. So seems a fair request to me.

fietserwin’s picture

I think the effect can be realized with a combination of aspect switcher, rotation and scaling effects.

sarah’s picture

Actually, I'd love to see this implemented. At the moment, I'm trying to achieve this using aspect switcher, scale and define canvas. Unfortunately, define canvas is exhibiting strange behaviour, so that method isn't working well for me (separate issue). I am also not keen to add 'borders' where it's not necessary.

I've come across use cases fairly frequently where the maximum allocated space for an image is known, being a little smaller is no problem, but the long side should match either the maximum width or the maximum height allocated for the image.

Cropping is not an option in at least two of my use cases, one being a photography club. In that instance, their artwork being scaled down is acceptable to the images' owners, but cropping a portion of the image is not approved at all!

fietserwin’s picture

Status: Active » Closed (works as designed)

It's even simpler then I thought in #5:

Create 3 styles:
a:2:{s:4:"name";s:35:"scale_long_and_short_side_landscape";s:7:"effects";a:1:{i:169;a:3:{s:4:"name";s:11:"image_scale";s:4:"data";a:3:{s:5:"width";s:3:"600";s:6:"height";s:3:"400";s:7:"upscale";i:0;}s:6:"weight";s:1:"1";}}}

a:2:{s:4:"name";s:34:"scale_long_and_short_side_portrait";s:7:"effects";a:1:{i:170;a:3:{s:4:"name";s:11:"image_scale";s:4:"data";a:3:{s:5:"width";s:3:"400";s:6:"height";s:3:"600";s:7:"upscale";i:0;}s:6:"weight";s:1:"1";}}}

a:2:{s:4:"name";s:25:"scale_long_and_short_side";s:7:"effects";a:1:{i:171;a:3:{s:4:"name";s:20:"canvasactions_aspect";s:4:"data";a:3:{s:8:"portrait";s:34:"scale_long_and_short_side_portrait";s:9:"landscape";s:35:"scale_long_and_short_side_landscape";s:16:"ratio_adjustment";s:1:"1";}s:6:"weight";s:2:"-9";}}}

Enable image styles admin (sub)module and import these styles. Change the width and height parameters to your required maximum dimensions in both sub styles.

If this is not what you are looking for, please come with some examples (as in #3).

sarah’s picture

Thank you. :o)

I am playing with the settings - I have a feeling some of the issues I'm having are related to the aspect switcher and/or canvas, but need to find time to test and confirm.