What is the best way to crop or mask an image into a circular shape, using either ImageMagick or GD libraries? (Note, solution exists on "other" Q&A sites, but not StackOverflow)
Here is one way with ImageMagick that will acomplish this without using a mask:
convert -size 200x200 xc:none -fill walter.jpg -draw "circle 100,100 100,1" circle_thumb.png


For those who need to do this in pure PHP using Imagick, you will need to refer to this question : circularize an image with imagick
Hope this will help.
J.
For those who wants a solution in PHP, providing the picture already cropped into a circle:
// convert the picture
$w = 640; $h=480; // original size
$original_path="/location/of/your/original-picture.jpg";
$dest_path="/location/of/your/picture-crop-transp.png";
$src = imagecreatefromstring(file_get_contents($original_path));
$newpic = imagecreatetruecolor($w,$h);
imagealphablending($newpic,false);
$transparent = imagecolorallocatealpha($newpic, 0, 0, 0, 127);
$r=$w/2;
for($x=0;$x<$w;$x++)
for($y=0;$y<$h;$y++){
$c = imagecolorat($src,$x,$y);
$_x = $x - $w/2;
$_y = $y - $h/2;
if((($_x*$_x) + ($_y*$_y)) < ($r*$r)){
imagesetpixel($newpic,$x,$y,$c);
}else{
imagesetpixel($newpic,$x,$y,$transparent);
}
}
imagesavealpha($newpic, true);
imagepng($newpic, $dest_path);
imagedestroy($newpic);
imagedestroy($src);
For those who want a node/js based solution, you can create a circular crop at specified coordinates using node-gm like this:
gm(original)
.crop(233, 233,29,26)
.resize(size, size)
.write(output, function(err) {
gm(size, size, 'none')
.fill(output)
.drawCircle(size/2,size/2, size/2, 0)
.write(output, function(err) {
console.log(err || 'done');
});
});
You can use a lib like JCrop (demo) to allow the user to crop the image on the front-end and pass the coordinates (w,h,x,y) into crop().
You can use this function if you want to circular the corners of an image. To make the circle image, you need to set $Radius to 50%; If the $source_url is a square, the output will be the circle, otherwise it will be oval.The output will be a PNG file with transparent background.
public function Crop_ByRadius($source_url,$destination_url="",$Radius="0px" ,$Keep_SourceFile = TRUE){
/*
Output File is png, Because for crop we need transparent color
if success :: this function returns url of Created File
if Fial :: returns FALSE
$Radius Input Examples ::
100 => 100px
100px => 100px
50% => 50%
*/
if( !file_exists($source_url) || $Radius == NULL )
return FALSE;
if( $destination_url == NULL || $destination_url == "" ) $destination_url = $source_url;
$PathInfo = pathinfo($destination_url);
$destination_url = $PathInfo['dirname'].DIRECTORY_SEPARATOR.$PathInfo['filename'].".png";
$ImageInfo = getimagesize($source_url);
$w = $ImageInfo[0];
$h = $ImageInfo[1];
$mime = $ImageInfo['mime'];
if( $mime != "image/jpeg" && $mime != "image/jpg" && $mime != "image/png")
return FALSE;
if( strpos($Radius,"%") !== FALSE ){
//$Radius by Cent
$Radius = intval( str_replace("%","",$Radius) );
$Smallest_Side = $w <= $h ? $w : $h;
$Radius = $Smallest_Side * $Radius / 100;
}else{
$Radius = strtolower($Radius);
$Radius = str_replace("px","",$Radius);
}
$Radius = is_numeric($Radius) ? intval($Radius) : 0;
if( $Radius == 0 ) return FALSE;
$src = imagecreatefromstring(file_get_contents($source_url));
$newpic = imagecreatetruecolor($w,$h);
imagealphablending($newpic,false);
$transparent = imagecolorallocatealpha($newpic, 0, 0, 0, 127);
//$transparent = imagecolorallocatealpha($newpic, 255, 0, 0, 0);//RED For Test
$r = $Radius / 2;
/********************** Pixel step config ********************************/
$Pixel_Step_def = 0.4;//smaller step take longer time! if set $Pixel_Step=0.1 result is better than $Pixel_Step=1 but it take longer time!
//We select the pixels we are sure are in range, to Take up the bigger steps and shorten the processing time
$Sure_x_Start = $Radius +1;
$Sure_x_End = $w - $Radius -1;
$Sure_y_Start = $Radius +1;
$Sure_y_End = $h - $Radius -1;
if( $w <= $h ){
//We want to use the larger side to make processing shorter
$Use_x_Sure = FALSE;
$Use_y_Sure = TRUE;
}else{
$Use_x_Sure = TRUE;
$Use_y_Sure = FALSE;
}
/********************** Pixel step config END********************************/
$Pixel_Step = $Pixel_Step_def;
for( $x=0; $x < $w ; $x+=$Pixel_Step ){
if( $Use_x_Sure && $x > $Sure_x_Start && $x < $Sure_x_End ) $Pixel_Step = 1;else $Pixel_Step = $Pixel_Step_def;
for( $y=0; $y < $h ; $y+=$Pixel_Step){
if( $Use_y_Sure && $y > $Sure_y_Start && $y < $Sure_y_End ) $Pixel_Step = 1;else $Pixel_Step = $Pixel_Step_def;
$c = imagecolorat($src,$x,$y);
$_x = ($x - $Radius) /2;
$_y = ($y - $Radius) /2;
$Inner_Circle = ( ( ($_x*$_x) + ($_y*$_y) ) < ($r*$r) );
$top_Left = ($x > $Radius || $y > $Radius) || $Inner_Circle;
$_x = ($x - $Radius) /2 - ($w/2 - $Radius);
$_y = ($y - $Radius) /2;
$Inner_Circle = ( ( ($_x*$_x) + ($_y*$_y) ) < ($r*$r) );
$top_Right = ($x < ($w - $Radius) || $y > $Radius) || $Inner_Circle;
$_x = ($x - $Radius) /2;
$_y = ($y - $Radius) /2 - ($h/2 - $Radius);
$Inner_Circle = ( ( ($_x*$_x) + ($_y*$_y) ) < ($r*$r) );
$Bottom_Left = ($x > $Radius || $y < ($h - $Radius) ) || $Inner_Circle;
$_x = ($x - $Radius) /2 - ($w/2 - $Radius);
$_y = ($y - $Radius) /2 - ($h/2 - $Radius);
$Inner_Circle = ( ( ($_x*$_x) + ($_y*$_y) ) < ($r*$r) );
$Bottom_Right = ($x < ($w - $Radius) || $y < ($h - $Radius) ) || $Inner_Circle;
if($top_Left && $top_Right && $Bottom_Left && $Bottom_Right ){
imagesetpixel($newpic,$x,$y,$c);
}else{
imagesetpixel($newpic,$x,$y,$transparent);
}
}
}
if( !$Keep_SourceFile && $source_url != $destination_url){
unlink($source_url);
}
imagesavealpha($newpic, true);
imagepng($newpic, $destination_url);
imagedestroy($newpic);
imagedestroy($src);
return $destination_url;
}
来源:https://stackoverflow.com/questions/999251/crop-or-mask-an-image-into-a-circle