4

Is there any PHP/GD function that can calculate this:

Input: image width, image height and an aspect ratio to honor. Output: the width/height of the max centered crop that respects the given aspect ratio (despite image original aspect ratio).

Example: image is 1000x500, a.r. is 1.25: max crop is 625x500. image is 100x110, max crop is: 80x110.

y2k-shubham
  • 10,183
  • 11
  • 55
  • 131

2 Answers2

10

There is no function that calculates this because it's elementary math:

$imageWidth = 1000;
$imageHeight = 500;
$ar = 1.25;

if ($ar < 1) { // "tall" crop
    $cropWidth = min($imageHeight * $ar, $imageWidth);
    $cropHeight = $cropWidth / $ar;
}
else { // "wide" or square crop
    $cropHeight = min($imageWidth / $ar, $imageHeight);
    $cropWidth = $cropHeight * $ar;
}

See it in action.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Thanks. I've spent a couple of minutes and arrived to something like your code (but your solution is more elegant). Yeah, elementary but yet useful. –  Dec 17 '11 at 00:00
  • Very nice solution. Even though my brain completely blanks out when i try to understand it, it works like a charm. – SquareCat Nov 17 '12 at 10:27
2

As an extension to @Jon's answer, here's an implementation of this approach in PHP-GD library

/**
 * Crops image by taking largest area rectangle from center of image so that the desired aspect ratio is realized.
 * @param resource $src_image image resource to be cropped
 * @param float $required_aspect_ratio Desired aspect ratio to be achieved via cropping
 * @return resource cropped image
 */
public function withCenterCrop($src_image, float $required_aspect_ratio) {
    $crr_width = imagesx($src_image);
    $crr_height = imagesy($src_image);
    $crr_aspect_ratio = $crr_width / $crr_height;

    $cropped_image = null;
    if ($crr_aspect_ratio < $required_aspect_ratio) {
        // current image is 'taller' (than what we need), it must be trimmed off from top & bottom
        $new_width = $crr_width;
        $new_height = $new_width / $required_aspect_ratio;
        // calculate the value of 'y' so that central portion of image is cropped
        $crop_y = (int) (($crr_height - $new_height) / 2);
        $cropped_image = imagecrop(
            $src_image,
            ['x' => 0, 'y' => $crop_y, 'width' => $new_width, 'height' => $new_height]
        );
    } else {
        // current image is 'wider' (than what we need), it must be trimmed off from sides
        $new_height = $crr_height;
        $new_width = $new_height * $required_aspect_ratio;
        // calculate the value of 'x' so that central portion of image is cropped
        $crop_x = (int) (($crr_width - $new_width) / 2);
        $cropped_image = imagecrop(
            $src_image,
            ['x' => $crop_x, 'y' => 0, 'width' => $new_width, 'height' => $new_height]
        );
    }

    return $cropped_image;
}
y2k-shubham
  • 10,183
  • 11
  • 55
  • 131