Closed (works as designed)
Project:
ImageCache Actions
Version:
7.x-1.x-dev
Component:
Code
Priority:
Minor
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
8 Sep 2012 at 15:10 UTC
Updated:
6 Aug 2013 at 13:19 UTC
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
Comment #1
fietserwinLooks like "scale and crop" from the core effects? If not can you post some examples and/or a more exhaustive description?
Comment #2
paulmicha commentedNope : 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).
Comment #3
fietserwinForgive 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
Comment #4
fietserwinI 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.
Comment #5
fietserwinI think the effect can be realized with a combination of aspect switcher, rotation and scaling effects.
Comment #6
sarah commentedActually, 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!
Comment #7
fietserwinIt'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).
Comment #8
sarah commentedThank 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.