Merge two images / replicating Photoshop's "resize canvas"?

IMagick is a native PHP extension to create and modify images using the ImageMagick API. ImageMagick Studio LLC did not write nor does it maintain the IMagick extension, however, IMagick users are welcome to discuss the extension here.
Jack-S

Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

Hi,
First of all, is there any built in function that does a similar job to Photoshop's resize canvas tool. i.e. It takes a width, height, and location (south west, south...north...center etc.) and crops/increases the height and with of the images "canvas", without scaling the actual image?

I couldn't find one, so decided to write my own, but I can't work out how to do it. I think setImageExtent can be used to increase the canvas (that right?), however it doesn't allow you to set where the original image should be positioned in the new size.

So instead I've tried to create a new image which is the target size, and then somehow copy the original into that, but I can't find the method for copying one image into another (and specifying the location). Any ideas?

Thanks,
Jack

EDIT:
With thanks to mkoppanen, the extentImage method has now been added to IMagick. This makes is easy to resize the image "canvas". For anyone after a method that auto calculates the x and y based on a gravity constant (like Photoshop does) check out my function here: viewtopic.php?p=30475#p30475
Last edited by Jack-S on 2007-10-01T08:49:04-07:00, edited 1 time in total.
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

OK, I figured out one way to do it, but there could be a better way. Any guidance on this would be great:

Code: Select all

class Jack_Imagick extends Imagick
{
	public function resizeCanvasImage($widthB, $heightB, $gravity, ImagickPixel $backgroundColor = null)
	{
		$widthA = $this->getImageWidth();
		$heightA = $this->getImageHeight();		
		switch ($gravity) {
			case Imagick::GRAVITY_CENTER:
				$x = floor(($widthB - $widthA) / 2);
				$y = floor(($heightB - $heightA) / 2);
			break;
			// ...
			default:
				// error
			break;
		}
		$draw = new ImagickDraw();
		$draw->setFillColor((isset($backgroundColor)) ? $backgroundColor : $this->getImageBackgroundColor());
		$draw->rectangle(0, 0, $widthB, $heightB);
		$draw->composite(Imagick::COMPOSITE_OVER, $x, $y, $widthA, $heightA, $this);
		$this->setImageExtent($widthB, $heightB);
		$this->drawImage($draw);
	}
}
P.S. Any ideas where I can get a win32 2.0.0rc4 dll for PHP 5.2.4?

Edit: Hmmmm, I really need to find a better way to do this. This function is REALLY slow, especially on large images.
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

OK, I've tried another approach now, which is a lot faster. Again, any advice on the best way to do this is appreciated.

Code: Select all

public function resizeCanvasImage($widthB, $heightB, $gravity = Imagick::GRAVITY_CENTER, ImagickPixel $backgroundColor = null)
{
	$widthA = $this->getImageWidth();
	$heightA = $this->getImageHeight();		
	switch ($gravity) {
		case Imagick::GRAVITY_CENTER:
			$x = floor(($widthB - $widthA) / 2);
			$y = floor(($heightB - $heightA) / 2);
		break;
		// @todo
		default:
			throw new Jack_Imagick_Exception("Gravity setting '$gravity' unknown");
		break;
	}
	if ($x > 0) {
		$this->setImageExtent($widthB, $heightA);
		$this->rollImage($x, 0);
	} else {
		$this->rollImage($x, 0);
		$this->setImageExtent($widthB, $heightA);
	}
	if ($y > 0) {
		$this->setImageExtent($widthB, $heightB);
		$this->rollImage(0, $y);
	} else {
		$this->rollImage(0, $y);
		$this->setImageExtent($widthB, $heightB);
	}
}
mkoppanen
Posts: 309
Joined: 2007-06-09T07:06:32-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by mkoppanen »

The latter way looks pretty good to me. My assumption is that that is the closest you get to resize canvas. If I understood the "resize canvas" correctly.
Mikko Koppanen
My blog: http://valokuva.org
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

Great thanks.

There is still one problem though. When setImageExtent increases the image size the additional space is filled with black. How can I change this colour? I though setImageBackgroundColor would do it, but it doesn't work. Any ideas? I'm using 2.0.0rc1 presently.
mkoppanen
Posts: 309
Joined: 2007-06-09T07:06:32-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by mkoppanen »

Jack-S wrote:Great thanks.

There is still one problem though. When setImageExtent increases the image size the additional space is filled with black. How can I change this colour? I though setImageBackgroundColor would do it, but it doesn't work. Any ideas? I'm using 2.0.0rc1 presently.

What is the image format? If you set transparent on jpeg image I think that is shown as black.

Try with png image and use:

Code: Select all

$im->setImageMatte( true );
$im->setImageBackgroundColor( new ImagickPixel( "transparent" ) );
Mikko Koppanen
My blog: http://valokuva.org
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

The source and target are JPEG yeah. Shouldn't there be a way to set the colour though, even with JPEG's?
mkoppanen
Posts: 309
Joined: 2007-06-09T07:06:32-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by mkoppanen »

Jack-S wrote:The source and target are JPEG yeah. Shouldn't there be a way to set the colour though, even with JPEG's?
Yes, of course. Try setting the background to white. In my opinion that should work. I can test that a little later if it doesn't work for you.
Mikko Koppanen
My blog: http://valokuva.org
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

Yeah, it dosen't seem to work, these both result in an image with a black area:

Code: Select all

$imagick = new Imagick('1.jpg'); // a 400x400px image
$imagick->setImageBackgroundColor(new ImagickPixel('white'));
$imagick->setImageExtent(800, 800);

Code: Select all

$imagick = new Imagick('1.png'); // a 400x400px image
$imagick->setImageMatte(true);
$imagick->setImageBackgroundColor(new ImagickPixel('transparent'));
$imagick->setImageExtent(800, 800);
mkoppanen
Posts: 309
Joined: 2007-06-09T07:06:32-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by mkoppanen »

Seems like setting background color does not affect extent. You could ask in general forum how to set the image extent color.

You can also try this code:

Code: Select all

function resizeCanvasImage( Imagick $image, $widthB, $heightB, $gravity, ImagickPixel $backgroundColor = null )
{
	$composite = new Imagick();
	$composite->newImage( $widthB, $heightB, new ImagickPixel( "white" ) );

	$widthA = $this->getImageWidth();
	$heightA = $this->getImageHeight();      
	switch ($gravity) {
	 case Imagick::GRAVITY_CENTER:
		$x = floor(($widthB - $widthA) / 2);
		$y = floor(($heightB - $heightA) / 2);
	 break;
	 // ...
	 default:
		// error
	 break;
	}

	return $composite->compositeImage( $image, Imagick::COMPOSITE_OVER, $x, $y );
}
Might be a little slower thou.
Mikko Koppanen
My blog: http://valokuva.org
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

Yeah, that is similar to the approach I originally tried, however it was a lot slower. I'll have a look in the general forum.
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

OK,
According to this page: http://www.imagemagick.org/Usage/crop/#extent, -extent allows you to set the background colour. I have no idea how the command line arguments of ImageMagick relate to the IMagick PHP extensions interface, but it seems that it should be possible with the background colour setting, so is this an ImageMagick issue or an IMagick issue?

Also, as of ImageMagick 6.3.2 -extent now supports the gravity setting, which (if supported by the IMagick:setImageExtent method) would remove the need for my custom method anyway, which would be great :) !

Any chance this could be added?
Thanks,
Jack

P.S. I am using Imagick 2.0.0rc, with ImageMagick 6.3.3 04/21/07 Q16
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by el_supremo »

Magickwand has two functions which deal with background colour. One is MagickSetImageBackgroundColor and the other is MagickSetBackgroundColor.
If IMagick also has a setBackgroundColor function I think you'll find that it is the one you need.

Pete
Jack-S

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by Jack-S »

el_supremo wrote:Magickwand has two functions which deal with background colour. One is MagickSetImageBackgroundColor and the other is MagickSetBackgroundColor.
If IMagick also has a setBackgroundColor function I think you'll find that it is the one you need.
Yes it does, however it doesn't seem to work: viewtopic.php?p=30419#p30419

Edit: setBackgroundColor() doesn't work either.
mkoppanen
Posts: 309
Joined: 2007-06-09T07:06:32-07:00

Re: Merge two images / replicating Photoshop's "resize canvas"?

Post by mkoppanen »

el_supremo wrote:Magickwand has two functions which deal with background colour. One is MagickSetImageBackgroundColor and the other is MagickSetBackgroundColor.
If IMagick also has a setBackgroundColor function I think you'll find that it is the one you need.

Pete
Seems like neither of them helps in this case. MagickSetBackgroundColor sets the background color for the whole wand and MagickSetImageBackgroundColor sets for single image (if I understood correctly).

Could this be a bug?

Jack-S wrote: Also, as of ImageMagick 6.3.2 -extent now supports the gravity setting, which (if supported by the IMagick:setImageExtent method) would remove the need for my custom method anyway, which would be great :) !
http://imagemagick.org/api/magick-image ... mageExtent

The api does not support setting gravity so I assume that just calling rollImage and setImageExtent.
Mikko Koppanen
My blog: http://valokuva.org
Post Reply