• 0

[PHP] Help with imagecopyresampled


Question

How can I crop the central part of a long image in to a square?

Say I have an image that looks like this:

 

post-360412-0-00896300-1379708207.png

 

I would like to crop it's center in to a square like this:

 

post-360412-0-45203900-1379708210.png

 

Here is the PHP code that I am using but am having no joy whatsoever.

 

if($OriginalHeight > $OriginalWidth){
   $StartY = $OriginalHeight / 4;
   $StartX = 0;
   $EndY = $StartY * 3;
   $EndX = $OriginalWidth;
}


if($OriginalHeight < $OriginalWidth){
   $StartY = 0;
   $StartX = $OriginalWidth / 4;
   $EndY = $OriginalHeight;
   $EndX = $StartX * 3;
}


if($OriginalHeight == $OriginalWidth){
   $StartY = 0;
   $StartX = $OriginalWidth;
   $EndY = $OriginalHeight;
   $EndX = $OriginalHeight;
}

imagecopyresampled($NewImage, $SrcImage, $EndX, $EndY, $StartX, $StartY, $NewImageSize, $NewImageSize, $OriginalWidth, $OriginalHeight);
 

Can a PHP expert help me?

Link to comment
Share on other sites

11 answers to this question

Recommended Posts

  • 0

Your logic is flawed. If we look at the first if block where we need to reduce the height, you are always setting the top and bottom positions to 1/4 and 3/4 respectively of the height of the image, i.e. where the image is taller than it is wide, you are always trying to change the height to 1/2 of whatever it currently is, which is not going to produce the desired outcome. Instead you should be thinking, right, it's this much too tall, so I need to trim half of that excess from the top and half from the bottom. I.e.

$excess = $OriginalHeight - $OriginalWidth;
$StartY = $excess / 2;
$EndY =  $StartY + $OriginalWidth;
$StartX = 0;
$EndX = $OriginalWidth;

Except this isn't necessarily quiet good enough, you need to consider properly what happens when excess is an ODD value. If excess is an odd value, then $StartY and $EndY are going to have 0.5 of a pixel that needs to be handled somehow. With the above code which doesn't do anything about this, what will happen? Is this simply going to get rounded up by a function at some point in the execution of your code, is it going to get rounded down by a function at some point, or could these non-whole numbers even cause a crash of your code by something expecting a whole number (more likely to happen in stricter languages than php)... It wouldn't reflect well on you as a programmer to simply do a little test to ensure it doesn't crash and then just leave it as that thinking I don't give a damn whether it's rounded up or down, i'll leave it to just do whatever it does; not taking the time to properly handle this now could come back to bite you later! All you need to do to handle it is first make a decision on whether you want it to round up or down (trim the extra pixel from the bottom or top respectively) and then simply round up/down:

$excess = $OriginalHeight - $OriginalWidth;

$StartY = round(($excess / 2), 0, PHP_ROUND_HALF_DOWN);

$EndY =  $StartY + $OriginalWidth;

$StartX = 0;

$EndX = $OriginalWidth;
Link to comment
Share on other sites

  • 0

Thanks theblazingangel, you bring up a good point.

Here is what I am now getting with your example code.

Right, I've never really done image manipulation in PHP before and assumed that imagecopyresampled was your own custom function and you were undoubtedly using correctly, but I see now that it's not and you're not (it was late, forgive me :p ).

You need to tell the function the portion of the original image to copy and where to in the new image. With the 5th and 6th parameters this means providing x and y for the top left corner of that source area ($StartX and $StartY respectively), as you have. In the 9th and 10th parameters you need to specify how wide and tall the area to copy is, for this you need to modify my if statement to capture these (capturing $EndX and $EndY values is pointless). For the 3rd and 4th parameters you need to specify the top left corner in the destination image to copy to. The ability to specify this allows you to build a new image from multiple pieces, in your case these should just simply both be zero though. The 7th and 8th parameters define the width and height of the area in the destination to copy to, these should be the same as the 9th and 10th parameters, if you specify anything different it would stretch/shrink the image to fit.

Link to comment
Share on other sites

  • 0

This code is a bit messy it's from a big image uploading class I made a while ago which I'm considering putting on GitHub or something. I probably should it does reszing, cropping etc all in a php class and it'll choose between Imagick or GD depending on what's available. I'm not sure if this is all of what ya need tbh.I'm very tired right now and I may have missed something. This is pretty much the math you need though. It also resizes the image, you'd need to edit this to take out that feature if ya don't need it.

	// For $ImageLocation you may want to use something like
	// $_FILES["file"]["tmp_name"]
	list($width, $height) = getimagesize($YourImageLocation);

	$maxWidth	= 50;
	$maxHeight	= 50;
	$xRatio		= $maxWidth / $width;
	$yRatio		= $maxHeight / $height;
	
	if($width > $maxWidth || $height > $maxHeight) {
		if ($xRatio * $height < $maxHeight) {
			// Resize the image based on width
			$tnHeight	= ceil($xRatio * $height);
			$tnWidth	= $maxWidth;
		} else {
			// Resize the image based on height
			$tnWidth	= ceil($yRatio * $width);
			$tnHeight	= $maxHeight;
		}
	} else {
		$tnWidth = $width;
		$tnHeight = $height;
	}


	// Create Medium sized thumbnails and small thumbnails
	// We need to crop, so we set both offsets to 0 first
	$offsetX = $offsetY = 0;

	// What ratio do we want to crop the image to, e.g. 16:9
	// Both thumbnails will be cropped so we do that first.
	$cropRatio = "1:1";
	$cropRatio = explode(':', (string) $cropRatio);

	$cropRatioComputed	= (float) $cropRatio[0] / (float) $cropRatio[1];
	$cropRatioComputed =  round($cropRatioComputed);

	if ($tnHeight > $tnWidth) {
		// Image is too tall so we will crop the top and bottom
		$height		= $tnWidth / $cropRatioComputed;
		$offsetY	= ($origHeight - $height) / 2;

	} else if ($tnWidth > $tnHeight) {
		// Image is too wide so we will crop off the left and right sides
		$width		= $tnHeight * $cropRatioComputed;
		$offsetX	= ($origWidth - $width) / 2;
	}

	ImageCopyResampled($NewImage, $SrcImage, 0, 0, $offsetX, $offsetY, $tnWidth, $tnHeight, $width, $height);
Link to comment
Share on other sites

  • 0

I hope you don't mind writing that last line out for me? I got a little confused.

I was hoping you could do it yourself to help you learn, I'll do it a bit later when I'm home if you still need me to. see below...

Link to comment
Share on other sites

  • 0

I hope you don't mind writing that last line out for me? I got a little confused.

here:

if ($OriginalHeight > $OriginalWidth) {
	$excess = $OriginalHeight - $OriginalWidth;
	$StartY = round(($excess / 2), 0, PHP_ROUND_HALF_DOWN);
	$StartX = 0;
	$NewWidth = $NewHeight = $OriginalWidth;
	
} elseif ($OriginalHeight < $OriginalWidth) {

	$excess = $OriginalWidth - $OriginalHeight;
	$StartX = round(($excess / 2), 0, PHP_ROUND_HALF_DOWN);
	$StartY = 0;
	$NewWidth = $NewHeight = $OriginalHeight;

} else {

	$StartY = $StartX = 0;
	$NewWidth = $NewHeight = $OriginalWidth;
}

imagecopyresampled($NewImage, $SrcImage, 0, 0, $StartX, $StartY, $NewWidth, $NewHeight, $NewWidth, $NewHeight);
Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.