0

Trying to take a rectangular photo, crop it into a square region, and then mask it into a circular with a transparent background.

//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)

$circle = new \Imagick();
$circle->newImage($dims['w'], $dims['h'], 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new \ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle($dims['w']/2, $dims['h']/2, $dims['w']/2, $dims['w']);
$circle->drawimage($draw);

$imagick = new \Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage($dims['w'], $dims['h'], $dims['x'], $dims['y']);
$imagick->compositeimage($circle, \Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($tempfile);
$imagick->destroy();

The result is the rectangular image, uncropped and without being circularized. What am I doing wrong?

Example image: enter image description here

Example input for $dims = {"x":253,"y":0,"x2":438.5,"y2":185.5,"w":185.5,"h":185.5}

Rough expected output:

enter image description here

Image i'm getting looks roughly like the input image.

Josh Nankin
  • 2,518
  • 4
  • 28
  • 45

4 Answers4

9

For those with an older version of Imagick (setimagematte does not exist in version lower than 6.2.9), I came up with an easy solution. The thing here is to copy opacity from the mask to the original image.

Original Image:

enter image description here

Mask:

enter image description here

Result:

enter image description here

The code:

$base = new Imagick('original.jpg');
$mask = new Imagick('mask.png');

$base->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$base->writeImage('result.png');

You could use an Imagick black circle as mask but I though it wasn't perfect so I used my own.

Of course you will certainly have to resize / crop your images but that's another story.

Hope this helps.

J.

Community
  • 1
  • 1
Jonathan Hell
  • 521
  • 1
  • 5
  • 15
4

Result of the code

This works for me:

<?php
//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)
$tempfile = 'VDSlU.jpg';
$outfile = 'blah.png';

$circle = new Imagick();
$circle->newImage(185.5, 185.5, 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle(185.5/2, 185.5/2, 185.5/2, 185.5);
$circle->drawimage($draw);

$imagick = new Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage(185.5, 185.5, 253, 0);
$imagick->compositeimage($circle, Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($outfile);
$imagick->destroy();
?>

<img src="blah.png">

I always try to keep the code simple until I get it working and then add all the variables etc. That could be the problem or there could be a problem with your version of Imagick.

It's namespaced

Still do not know what it means! - I am getting a bit behind with php as I do not use it very much these days.

Bonzo
  • 5,169
  • 1
  • 19
  • 27
  • hmm, yeah, I'll substitute values again and retry. thanks! also: http://php.net/manual/en/language.namespaces.php – Josh Nankin Dec 11 '12 at 17:29
  • also, for others coming here, i ended up just using css border-radius instead of doing this on the server side. – Josh Nankin Dec 11 '12 at 17:32
  • 1
    I wonder why the generated image seems cut on the right side and the bottom part. The circle isn't perfect. – user1240207 Aug 28 '16 at 03:46
  • The flats are probably due to the crop image dimensions. I did not get it perfect as it was an example and proved the process. – Bonzo Aug 28 '16 at 07:40
3

There's also another workaround that I suggest here :

// create an imagick object of your image
$image = new \Imagick('/absolute/path/to/your/image');
// crop square your image from its center (100px witdh/height in my example)
$image->cropThumbnailImage(100, 100);
// then round the corners (0.5x the width and height)
$image->roundCorners(50, 50);
// force the png format for transparency
$image->setImageFormat("png");
// write the new image
$image->writeImage('/absolute/path/to/your/new/image');
// done!

Many thanks to all previous answers and contributors that lead me to this code!

Feel free to test/comment my solution!

Ravi Misra
  • 196
  • 2
  • 8
Jeremy Jumeau
  • 199
  • 2
  • 4
1

I stumbled upon this as I was searching for a similar solution for Ruby on Rails, notice that this Stackoverflow question uses vignette instead which seems to be a much simpler way to solve the problem.

I used vignette to solve my problem with rounded images in Ruby on Rails using Dragonfly.

Community
  • 1
  • 1
Thomas Bindzus
  • 1,508
  • 12
  • 12