I want to crop a circle image using PHP but it seems that my new image have some transparent pixels. Of course, I want ONLY the outside area of the ellipse to have backgroun
You are cropping and removing black color ( or setting black as transparent ). Since your image has black color in it, it also gets removed.
Instead of removing the color, try to replace the outer layers color to, ie, pink and then set it to transparent.
I couln't get it done with Alain's code either. After some time understanding what each line of code does, here is my fix..
//this creates a pink rectangle of the same size
$mask = imagecreatetruecolor($imgwidth, $imgheight);
$pink = imagecolorallocate($mask, 255, 0, 255);
imagefill($mask, 0, 0, $pink);
//this cuts a hole in the middle of the pink mask
$black = imagecolorallocate($mask, 0, 0, 0);
imagecolortransparent($mask, $black);
imagefilledellipse($mask, $imgwidth/2, $imgheight/2, $imgwidth, $imgheight, $black);
//this merges the mask over the pic and makes the pink corners transparent
imagecopymerge($img, $mask, 0, 0, 0, 0, $imgheight, $imgheight);
imagecolortransparent($img, $pink);
imagepng($img, "my_circle.png");
There is several things to note :
As @DainisAbols suggested, it should be better to take an unusual color to for your transparency. Here, you are using black :
$red = imagecolorallocate($mask, 0, 0, 0);
imagecopymerge($image, $mask, 0, 0, 0, 0, $this->dst_w, $this->dst_h,100);
imagecolortransparent($image, $red);
Even if your var is called red, your R-G-B value is 0-0-0. Uncommon colors include flashy blue (0-0-255), flashy green (0-255-0), flashy yellow (255-255-0), flashy cyan (0-255-255) and flashy pink (255-0-255). Red is quite common everywhere and is not that flashy so I exclude it from those special colors.
Then, even if your images here are both true color's ones, that's a good practice to allocate a color for each image. In the example above, you create a $red
variable containing black for $mask
, but you're using it as transparency color in $image
.
Finally, you are drawing an ellipse which have the same radius as your image size, so you need to imagefill
each corners of your image and not only the top-left's one. In your example it works, but this is only because you selected black to be the transparent color.
Here is a full implementation.
<?php
class CircleCrop
{
private $src_img;
private $src_w;
private $src_h;
private $dst_img;
private $dst_w;
private $dst_h;
public function __construct($img)
{
$this->src_img = $img;
$this->src_w = imagesx($img);
$this->src_h = imagesy($img);
$this->dst_w = imagesx($img);
$this->dst_h = imagesy($img);
}
public function __destruct()
{
if (is_resource($this->dst_img))
{
imagedestroy($this->dst_img);
}
}
public function display()
{
header("Content-type: image/png");
imagepng($this->dst_img);
return $this;
}
public function reset()
{
if (is_resource(($this->dst_img)))
{
imagedestroy($this->dst_img);
}
$this->dst_img = imagecreatetruecolor($this->dst_w, $this->dst_h);
imagecopy($this->dst_img, $this->src_img, 0, 0, 0, 0, $this->dst_w, $this->dst_h);
return $this;
}
public function size($dstWidth, $dstHeight)
{
$this->dst_w = $dstWidth;
$this->dst_h = $dstHeight;
return $this->reset();
}
public function crop()
{
// Intializes destination image
$this->reset();
// Create a black image with a transparent ellipse, and merge with destination
$mask = imagecreatetruecolor($this->dst_w, $this->dst_h);
$maskTransparent = imagecolorallocate($mask, 255, 0, 255);
imagecolortransparent($mask, $maskTransparent);
imagefilledellipse($mask, $this->dst_w / 2, $this->dst_h / 2, $this->dst_w, $this->dst_h, $maskTransparent);
imagecopymerge($this->dst_img, $mask, 0, 0, 0, 0, $this->dst_w, $this->dst_h, 100);
// Fill each corners of destination image with transparency
$dstTransparent = imagecolorallocate($this->dst_img, 255, 0, 255);
imagefill($this->dst_img, 0, 0, $dstTransparent);
imagefill($this->dst_img, $this->dst_w - 1, 0, $dstTransparent);
imagefill($this->dst_img, 0, $this->dst_h - 1, $dstTransparent);
imagefill($this->dst_img, $this->dst_w - 1, $this->dst_h - 1, $dstTransparent);
imagecolortransparent($this->dst_img, $dstTransparent);
return $this;
}
}
Demo :
$img = imagecreatefromjpeg("test4.jpg");
$crop = new CircleCrop($img);
$crop->crop()->display();
Result :