Search code examples
imageimagemagickaspect-ratio

How to fit images within fixed aspect ratio without resizing or cropping with ImageMagick?


My photography website is connected to print services, but they only offer a few standard aspect ratios (2:3, 4:5, 1:1, etc.). Many of my photos use other aspect ratios, and are not offered as prints at all as a result.

To fix this, I'd like to use ImageMagick CLI or another tool to put the images on a canvas with a standard aspect ratio, say, 4:5. There must be no resampling or cropping of the source image at any stage, only the outer dimensions (canvas) may grow.

The concept I've come up with is:

  1. Take a source image with non-standard aspect ratio, and expand its canvas by 20% in all directions with white. This must be in relative terms due to varying source image sizes, as pixel dimensions would require resampling of the image.
  2. Set the resulting matted image inside another white canvas in 4:5 aspect ratio. Either vertical or horizontal sides would be cropped in most cases, but the crop would only affect the 20% white border, not the source image.

The output should be images of varying pixel dimensions, in a fixed 4:5 aspect ratio, with white borders around all four edges of varying thickness. I've created a sample page with before and after views on my website.

Due to wildly varying aspect ratios, I would have to run all my photos multiple times through the script with varying destination aspect ratios, and pick and choose the most balanced aspect ratio for each. Tedious, but I don't think there's a way to automate that.

Any idea how to accomplish this? Or better suggestions?

I'm using 6.x of IM in either Windows or Linux, not on a website.


Solution

  • I tend to work in php and am off to bed now but here is an example using php and version 7. As you can see in version 7 you can have some of the calculations within the command. On version 6 it will have to be a separate line saved into a variable and then the variable will be used in the command.

    Only tested quickly to see if it worked and I may have the landscape/portrate logic the wrong way around. But it should give you an idea how it could work.

    <?php
    // Setup the image to use
    $image = '_MG_4949.jpg';
    // Get the dimensions of the image into an array
    $size = getimagesize("$image");
    
    // Aspect array
    $aspect = array(.87, 1.45);
    
    // If landscape original image do this
    If ($size[0] > $size[1])    {
    foreach ( $aspect as $value )   { 
        exec("magick $image -background white -gravity center -extent \"%[fx:w*1.2]\"x\"%[fx:w*$value]\" $value.jpg"); 
                                    }
                            }
    // If portrate image do this
    else {
    foreach ( $aspect as $value )   { 
        exec("magick $image -background white -gravity center -extent \"%[fx:h*$value]\"x\"%[fx:h*1.2]\" $value.jpg"); 
                                    }
    }   
    ?>
    

    EDIT the above code should be OK now

    Here is a php version for V6 ( no php getimagesize function this time ) and both versions you should be able to convert to bash or batch files.

    // Setup the image to use
    $image = '_MG_6790.jpg';
    // Get the dimensions of the image into an array
    $height = exec("identify $image -ping -format %[fx:h] info:");
    $width = exec("identify $image -ping -format %[fx:w] info:");
    
    // Aspect array
    $aspect = array(.87, 1.45);
    
    // If landscape original image do this
    If ($width > $height)   {
    foreach ( $aspect as $value )   { 
        $newWidth = $width*1.2;
        $newHeight = $height*$value;
        exec("convert $image -background white -gravity center -extent {$newWidth}x{$newHeight} $value.jpg"); 
                                    }
                            }
    // If portrate image do this
    else {
    foreach ( $aspect as $value )   { 
        $newWidth = $width*$value;
        $newHeight = $height*1.2;
        exec("convert $image -background white -gravity center -extent {$newWidth}x{$newHeight} $value.jpg"); 
                                    }
    }