PHP GD如何圆形裁剪3个方形图像并合并为1个图像保持透明度

时间:2015-05-07 07:19:07

标签: php png transparency gd

我有2个源图像,我想:

  1. 对每个图像进行圆形裁剪,圆圈外部透明
  2. 将所有图像合并/复制回目标透明图像。
  3. 我尝试了many examples,但似乎无法保持最终图像的透明度。

    我试图实现这样的目标: enter image description here

    这是我得到的输出示例: enter image description here

    这是我的circle_crop函数:

        function create_circle( $img_path ) {
        // Attribution: by NerdsOfTech
    
        // Step 1 - Start with image as layer 1 (canvas).
        if (! $img1 = $this->imageCreateFromAny( $img_path )) {
            return FALSE;
        }
    
        $x=imagesx($img1);
        $y=imagesy($img1);
    
    
        // Step 2 - Create a blank image.
        $img2 = imagecreatetruecolor($x, $y);
    
        $bg = imagecolorallocate($img2, 255,0,255, 127); // wierdo pink background
        // $bg = imagecolorallocate($img2, 0, 0, 0, 127 ); // white background
    
        imagefill($img2, 0, 0, $bg);
        imagecolortransparent($img2, $bg);
    
        // Step 3 - Create the ellipse OR circle mask.
        $e = imagecolorallocate($img2, 255, 255, 255); // black mask color
    
        // Draw a ellipse mask
        imagefilledellipse ($img2, ($x/2), ($y/2), $x, $y, $e);
    
        // OR
        // Draw a circle mask
        // $r = $x <= $y ? $x : $y; // use smallest side as radius & center shape
        // imagefilledellipse ($img2, ($x/2), ($y/2), $r, $r, $e);
    
        // Step 4 - Make shape color transparent
        imagecolortransparent($img2, $e);
    
        // Step 5 - Merge the mask into canvas with 100 percent opacity
        imagecopymerge($img1, $img2, 0, 0, 0, 0, $x, $y, 100);
    
        // Step 6 - Make outside border color around circle transparent
        imagecolortransparent($img1, $bg);
    
        /* Clean up memory */
        imagedestroy($img2);
    
        return $img1;
    }
    

    以下是我在图片网址数组中传递的代码,并通过调用circle_crop函数循环返回裁剪后的图片并将其合并到目标图片上。

    function generate_collage( $img_name_path_array, $effect = 'POLAROID' ) {
        $base_img_width = 800;
        $base_img_height = 650;
    
        if (empty($img_name_path_array)) {
            error_log('Image name_path_array is blank?'.PHP_EOL);
            return FALSE;
        }
        $effect = strtoupper($effect);
    
        /* Create canvas */
        $collage_img = imagecreatetruecolor($base_img_width, $base_img_height);
        imagealphablending($collage_img, false);
        imagesavealpha($collage_img,true);
        /* Create alpha channel for transparent layer */
        $trans_col=imagecolorallocatealpha($collage_img,255,255,255, 127);
        /* Create overlapping transparent layer */
        imagefilledrectangle($collage_img,0,0,$base_img_width,$base_img_height,$trans_col);
    
        /* Continue to keep layers transparent */
        imagealphablending($collage_img,true);
    
        $size_reduction = .80;
        $start_size = 100;
    
    
        foreach ($img_name_path_array as $image_array ) {
            $img_text = $image_array[0];
            $img_path = $image_array[1];
            if (! empty($img_path)) {
                switch ($effect) {
                    /* Add other collage image effects here */
                    case 'POLAROID' : {
                        $temp_img = $this->create_polaroid($img_path, $img_text, TRUE);
                        break;
                    }
                    case 'CIRCLES' : {
                        // $temp_img = $this->circle_crop($img_path);
                        $temp_img = $this->create_circle($img_path);
                        break;
                    }
                    default : {
                        /* Default to polaroid for now */
                        $temp_img = $this->create_polaroid($img_path, $img_text, TRUE);
                        break;
                    }
                }
    
                if ($temp_img) {
                    /* Get original height and width paramaters */
                    $source_w = imagesx($temp_img);
                    $source_h = imagesy($temp_img);
    
                    /* Randomise X and Y coordinates */
                    $random_x_pos = rand(0, (int) ($base_img_width * .66));
                    $random_y_pos = rand(0, (int) ($base_img_height * .3));
    
                    /* Randomise image size */
                    $start_size = ($start_size * $size_reduction);
                    $random_img_size_ratio = $start_size / 100;
    
                    /* Add generated image to base collage image */
                    imagecopyresampled($collage_img, $temp_img, $random_x_pos, $random_y_pos, 0, 0, ($base_img_width * $random_img_size_ratio), ($base_img_height * $random_img_size_ratio), $source_w, $source_h);
    
                    imagecolortransparent($collage_img, $trans_col);
                    /* Keep transparent when saving */
                    imagesavealpha($collage_img,true);
    
                    /* Memory clean up */
                    imagedestroy($temp_img);
    
                    // break;
                }
            }
        }
    
    
        /* Now display PNG to browser */
        $this->show_png_from_image_object($collage_img);
    }
    

    这是我的显示功能:

    function show_png_from_image_object( $img_obj ) {
        header ( 'Content-Type: image/png' );
    
        /* Display PNG with max compression */
        imagepng ( $img_obj, NULL,  9, PNG_ALL_FILTERS);
        imagedestroy ( $img_obj );
    }
    

    我已经把头发拉了2天,所以任何指针都会非常感激。

    谢谢,杰森。

2 个答案:

答案 0 :(得分:6)

我已编写以下类来处理所有必需的图像处理:

@Autowired
public SomeObject initSomeObject(Object1 o1, Object2 o2, ...) {

如上所述,该类仅适用于PNG文件,但如果需要,您应该能够轻松地修改它。

示例类用法:

class Img
{
    public $img;

    public $transparent;

    public $width;

    public $height;

    public function __construct($img = null)
    {
        if (!empty($img)) {
            $this->img = imagecreatefrompng($img);
            $this->width = imagesx($this->img);
            $this->height = imagesy($this->img);
            $this->setTransparentColour();
        }
    }

    public function create($width, $height, $transparent)
    {
        $this->img = imagecreatetruecolor($width, $height);
        $this->width = $width;
        $this->height =$height;

        $this->setTransparentColour();

        if (true === $transparent) {
            imagefill($this->img, 0, 0, $this->transparent);
        }
    }

    public function setTransparentColour($red = 255, $green = 0, $blue = 255)
    {
        $this->transparent = imagecolorallocate($this->img, $red, $green, $blue);
        imagecolortransparent($this->img, $this->transparent);
    }

    public function circleCrop()
    {
        $mask = imagecreatetruecolor($this->width, $this->height);
        $black = imagecolorallocate($mask, 0, 0, 0);
        $magenta = imagecolorallocate($mask, 255, 0, 255);

        imagefill($mask, 0, 0, $magenta);

        imagefilledellipse(
            $mask,
            ($this->width / 2),
            ($this->height / 2),
            $this->width,
            $this->height,
            $black
        );

        imagecolortransparent($mask, $black);

        imagecopymerge($this->img, $mask, 0, 0, 0, 0, $this->width, $this->height, 100);

        imagedestroy($mask);
    }

    public function merge(Img $in, $dst_x = 0, $dst_y = 0)
    {
        imagecopymerge(
            $this->img,
            $in->img,
            $dst_x,
            $dst_y,
            0,
            0,
            $in->width,
            $in->height,
            100
        );
    }

    public function render()
    {
        header('Content-type: image/png');
        imagepng($this->img);
    }
}

这将导致下面的图像(当然,嵌入此处时无法看到透明度,因此请尝试单独打开图像):

Resultant image

我使用了这两个源图像:

Source image 1 Source image 2

答案 1 :(得分:1)

您可以使用ImageArtist一个GD包装器创建的图像操作非常容易使用php

$overlay = new Overlay(720, 480, new Color(34,34,36));
$w = $overlay->getWidth();
$h = $overlay->getHeight();

$mi = new CircularShape("./mi.jpg");
$mi->scale(21);
$mi->setAxises(60,60);
$mi->build();

$mali = new CircularShape("./mali.jpg");
$mali->scale(60);
$mali->setAxises(140,140);
$mali->build();

$bach = new CircularShape("./har.jpeg");
$bach->scale(40);
$bach->setAxises(80,80);
$bach->build();

$borderd = new CircularShape(new Overlay($bach->getWidth()+10,$bach->getHeight()+10,new Color(255,255,255)));
$borderd->build();
$bach = $borderd->merge($bach,5,5);

$img = $overlay->merge($mi,$w/2 + 60,120);
$img->merge($mali,170,60);
$img->merge($bach,$w/2,200);

$img->dump(); //this just for demo, but you can use other methods to save this to disk

目前ImageArtist不支持边框,但如果你的创意很少,则可以使用叠加层。 这是上面代码的输出。

enter image description here