Маска изображений с созданным изображением Imagick

Мне нужно знать, как можно замаскировать любое квадратное изображение с помощью Imagick. Вот код, который у меня есть, но изображение не маскируется должным образом:

Получить изображение

$srcFile = 'filename.png';
$image = new Imagick($srcFile);

Обрезать изображение на квадрат

$d = $image->getImageGeometry();
$src_width = $d['width'];
$src_height = $d['height'];
$thumbSize = min(max($src_width, $src_height), abs($thumbSize));
if ($src_width < $src_height) {
$image->cropImage($src_width, $src_width, 0, (($src_height - $src_width)/2));
} else {
$image->cropImage($src_height, $src_height, (($src_width - $src_height)/2), 0);
}

Изменить размер изображения

$image->thumbnailImage($thumbSize, $thumbSize, 1);

Обрезать / Маскировать изображение с безье

$image->compositeImage(bezier($thumbSize, $thumbSize), Imagick::COMPOSITE_COPYOPACITY, 0, 0);

Функция Безье создает форму, похожую на эту:

форма маски Безье

function bezier($width, $height) {
$fillColor = "#000";
$draw = new ImagickDraw();

Заполните немаскированную часть черным цветом

    $fillColor = new ImagickPixel($fillColor);
$draw->setFillColor($fillColor);
$smoothPointsSet = [
[
['x' => 0.0 * $width, 'y' => 0.5 * $width],
['x' => 0.0 * $width, 'y' => 0.905 * $width],
['x' => 0.095 * $width, 'y' => 1.0 * $width],
['x' => 0.5 * $width, 'y' => 1.0 * $width]
], [
['x' => 0.5 * $width, 'y' => 1.0 * $width],
['x' => 0.905 * $width, 'y' => 1.0 * $width],
['x' => 1.0 * $width, 'y' => 0.905 * $width],
['x' => 1.0 * $width, 'y' => 0.5 * $width]
], [
['x' => 1.0 * $width, 'y' => 0.5 * $width],
['x' => 1.0 * $width, 'y' => 0.095 * $width],
['x' => 0.905 * $width, 'y' => 0.0 * $width],
['x' => 0.5 * $width, 'y' => 0.0 * $width]
], [
['x' => 0.5 * $width, 'y' => 0.0 * $width],
['x' => 0.095 * $width, 'y' => 0.0 * $width],
['x' => 0.0 * $width, 'y' => 0.095 * $width],
['x' => 0.0 * $width, 'y' => 0.5 * $width]
]
];

foreach ($smoothPointsSet as $points) {
$draw->bezier($points);
}

Безье точки не заполняют квадрат в середине, поэтому заполните его вручную

    $points = [
['x' => $width * 0.5, 'y' => 0.0],
['x' => 0.0, 'y' => $height * 0.5],
['x' => $width * 0.5, 'y' => $height],
['x' => $width, 'y' => $height * 0.5]
];
$draw->polygon($points);

Скопируйте изображение ящика в новое прозрачное изображение Imagick

    $imagick = new Imagick();
$imagick->newImage($width, $width, "none");

С этого момента я экспериментировал с различными свойствами. Я не получил удовлетворительного результата — изображение почти всегда не маскируется.

    #$imagick->setImageAlphaChannel(Imagick::ALPHACHANNEL_SHAPE);
#$imagick->setImageFormat("png");

$imagick->drawImage($draw);

#$imagick->setImageMatte(false);

return $imagick;
}

Я был бы очень рад, если бы я мог знать, где проблема и как ее исправить. Я нашел различные ответы на SO, которые не работали для меня:

использование $dude->setImageMatte(1);
Использование прозрачного PNG в качестве маски клипа

использование $base->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA);
Как использовать Imagick для объединения и маскирования изображений?

К сожалению, я не смог решить проблему.

1

Решение

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

$mask = bezier($thumbSize, $thumbSize);

// Copy opacity mask
if ($image->getImageMatte()) {
$image->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA);
} else {
$image->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
}

$image->setImageBackgroundColor(new ImagickPixel('white'));
#$image->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE);
$image = $image->flattenImages();

В функции Безье:

$imagick = new Imagick();
$imagick->newImage($width, $width, "none");
$imagick->setImageBackgroundColor(new ImagickPixel('transparent'));
#$imagick->setImageAlphaChannel(Imagick::ALPHACHANNEL_SHAPE);
$imagick->setImageFormat("png");

//Render the draw commands in the ImagickDraw object
//into the image.
$imagick->drawImage($draw);
$imagick->negateImage(FALSE);return $imagick;
0

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

Других решений пока нет …