Page 1 of 2

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

Posted: 2007-09-29T03:55:15-07:00
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

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

Posted: 2007-09-29T05:00:59-07:00
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.

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

Posted: 2007-09-29T10:13:59-07:00
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);
	}
}

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

Posted: 2007-09-30T06:11:46-07:00
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.

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

Posted: 2007-09-30T06:43:11-07:00
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.

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

Posted: 2007-09-30T07:23:19-07:00
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" ) );

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

Posted: 2007-09-30T07:45:31-07:00
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?

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

Posted: 2007-09-30T07:49:02-07:00
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.

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

Posted: 2007-09-30T07:52:34-07:00
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);

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

Posted: 2007-09-30T08:27:49-07:00
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.

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

Posted: 2007-09-30T08:35:29-07:00
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.

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

Posted: 2007-09-30T08:47:27-07:00
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

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

Posted: 2007-09-30T08:53:51-07:00
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

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

Posted: 2007-09-30T09:02:19-07:00
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.

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

Posted: 2007-09-30T10:15:50-07:00
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.