Question

I don't use Imagemagick very often, which is why I don't know how to solve this problem. I also don't know how to phrase the question other than: How do I get the image to be cropped like the CSS property: background-size: contain; I haven't been able to find an answer, likely due to my phrasing.

I need the image to be 200px, and "resized/cropped" so that it is not stretched, but contained by the width or height (dependent on the orientation of the image width > height = contain by width)

What I have so far:

$im = new Imagick($path);

/* Resizing Operations */

$gm = $im->getImageGeometry();
$w = $gm['width'];
$h = $gm['height'];

if($h < $w) {
    $nh = 200;
    $nw = (200 / $h) * $w;
} else {
    $nw = 200;
    $nh = (200 / $w) * $h;
}

$im->resizeImage($nw, $nh, Imagick::FILTER_LANCZOS, true);
$im->cropThumbnailImage(200,200);

/* End Resizing Operations */

Which produces an image with the center chopped out.

Here's a visual example

We have this logo:

Original Logo


And then we want it to be constrained to 200px wide and 200px high, contained:

resized

Essentially like setting the canvas height, while not adjusting the image height.

Was it helpful?

Solution

Came up with this algorithm based on the extent method of ImageMagick, which achieves the same result as CSS's background-size: contain;

You can set the 200 value in the resizeImage function to get your end product. Works beautifully!

$im = new Imagick($path);

/* Resizing Operations */
$gm = $im->getImageGeometry();
$w = $gm['width'];
$h = $gm['height'];

if($h < $w) {
    $sr = $w;
    $horz = TRUE;
} else if($h > $w) {
    $sr = $h;
    $horz = FALSE;
} else {
    $square = TRUE;
}

if(!$square && $horz) {
    $srs = $sr / 2;
    $extent_amt = $srs - ($h / 2);
    $im->extentImage($sr, $sr, 0, 0 - $extent_amt);
} else if(!$square && !$horz) {
    $srs = $sr / 2;
    $extent_amt = $srs - ($w / 2);
    $im->extentImage($sr, $sr, 0 - $extent_amt, 0);
}

$im->resizeImage(200, 200, Imagick::FILTER_LANCZOS, true);

/* End Resizing Operations */

$im->writeImage($path);

/* Clean up time */
$im->clear();
$im->destroy();

OTHER TIPS

it seems like this would work for you, in that it operates in the same way that the background-size:contain; works in CSS

$path = __DIR__ . '/img.jpg';
$im = new Imagick($path);

$gm = $im->getImageGeometry();
$w = $gm['width'];
$h = $gm['height'];

if ($w >= $h) {
    $target_height = 0;
    $target_width = 200;
} elseif ($h > $w) {
    $target_height = 200;
    $target_width = 0;
}

$im->resizeImage($target_width, $target_height, Imagick::FILTER_LANCZOS, true);

$im->writeImage($path);
$im->clear();
$im->destroy();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top