png — PHP GD Как сделать круговую обрезку 3 квадратных изображений и объединить их в 1 изображение, сохраняя прозрачность

У меня есть 2 исходных изображения, и я хочу:

  1. Сделайте круговую обрезку каждого изображения, с внешней стороны круга прозрачным
  2. Объединить / скопировать все изображения обратно на целевое прозрачное изображение.

я пытался много примеров, но не могу сохранить прозрачность конечного изображения.

Я пытаюсь добиться чего-то вроде этого:
введите описание изображения здесь

Это пример вывода, который я получаю:
введите описание изображения здесь

Вот моя функция 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;
}

Вот код, который я передаю в массив URL-адресов изображений и перебираю вызов функции 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

Решение

Я написал следующий класс для обработки всех необходимых изображений:

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);
}
}

Как написано, класс будет работать только с файлами PNG, но вы сможете изменить это достаточно легко, если потребуется.

Пример использования класса:

// create a transparent base image that we will merge the cropped images into.
$img = new Img();
$img->create(400, 400, true);

// first image; crop and merge with base.
$img2 = new Img('./crop_1.png');
$img2->circleCrop();
$img->merge($img2, 50, 50);

// second image; crop and merge with base.
$img3 = new Img('./crop_2.png');
$img3->circleCrop();
$img->merge($img3, 25, 200);

$img->render();

Это приведет к изображению ниже (конечно, прозрачность не видна, когда встроена здесь, поэтому попробуйте открыть изображение отдельно):

Результирующее изображение

Я использовал эти два исходных изображения:

Исходное изображение 1
Исходное изображение 2

6

Другие решения

ты можешь использовать 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 не поддерживает границы, но если вы не очень креативны, вы можете использовать оверлей.
Вот вывод приведенного выше кода.

введите описание изображения здесь

1

По вопросам рекламы [email protected]