我正在尝试将我的文件上传为圆圈,但无法使其工作。 我看过一些有关对图像应用蒙版的主题,但是当我应用蒙版时,它需要很长时间并且服务器会关闭请求。
我正在使用 Laravel 的
Intervention Image
库
我的代码如下:
$identifier = "{$this->loggedUser->id}" . str_random(9) . ".{$file->getClientOriginalExtension()}";
$mask = $this->createCircleMask(200, 200);
$thumbMask = $this->createCircleMask(40, 40);
Image::make($file->getRealPath())->mask($mask)->save(public_path("images/profile/{$identifier}"));
Image::make($file->getRealPath())->mask($thumbMask)->save(public_path("images/profile/thumbs/{$identifier}"));
createCircleMask
方法如下所示:
public function createCircleMask($width, $height)
{
$circle = Image::canvas($width, $height, '#000000');
return $circle->circle($width - 1, $width / 2, $height / 2);
}
这是一个适用于我的情况的函数。但仅如果我使用 imagick 驱动程序。标准 gd 库非常非常慢,至少在我的测试计算机上是这样。 您可以查看vendor\intervention\image\src\Intervention\Image\Gd\Commands\MaskCommand.php以找出原因。
public function upload() {
$path = storage_path('app')."/";
$image = \Image::make(\Input::file('image'));
$image->encode('png');
/* if you want to have a perfect and complete circle using the whole width and height the image
must be shaped as as square. If your images are not guaranteed to be a square maybe you could
use Intervention's fit() function */
// $image->fit(300,300);
// create empty canvas
$width = $image->getWidth();
$height = $image->getHeight();
$mask = \Image::canvas($width, $height);
// draw a white circle
$mask->circle($width, $width/2, $height/2, function ($draw) {
$draw->background('#fff');
});
$image->mask($mask, false);
$image->save($path."circled.png");
}
对于那些在 Laravel 中使用
intervention/image
v3 的人来说,由于 mask
方法已被删除,我们可以使用自定义类来完成这项工作。
<?php
namespace App\Helpers\Image;
class CircleImage
{
public $img;
public $width;
public $height;
public $minSize;
public function __construct($img = null)
{
if (!empty($img)) {
$this->img = imagecreatefromstring($img);
$this->width = imagesx($this->img); // Image original width
$this->height = imagesy($this->img); // Image original height
// Get the minimum size
// This will help cut the image in a circular shape
$this->minSize = min($this->width, $this->height);
}
}
public function make(): string
{
$radius = $this->minSize / 2;
// First we crop the image from center
$cropped = imagecrop($this->img, [
// Calculation summary:
// here width/2 gives us the center point, suppose our image width is 200,
// Then the center point is 100, now we want our cropping to start
// at negative $radius from 100 and end at positive $radius from 100,
// So that it crops from the center part into a square with the
// Diameter same as minSize (Same for height)
"x" => $this->width / 2 - $radius,
"y" => $this->height / 2 - $radius,
"width" => $this->minSize, // Diameter
"height" => $this->minSize, // Diameter
]);
if ($cropped !== false) { // in case a new image object was returned
imagedestroy($this->img); // we destroy the original image
$this->img = $cropped; // and assign the cropped image
} else {
throw new \Exception("Failed to crop the image!", 500);
}
// Now create the circular mask
$mask = imagecreatetruecolor($this->minSize, $this->minSize);
$black = imagecolorallocate($mask, 0, 0, 0);
$magenta = imagecolorallocate($mask, 255, 0, 255);
// Fill with magenta color
imagefill($mask, 0, 0, $magenta);
// Create a black circle in the center
imagefilledellipse(
$mask,
$radius,
$radius,
$this->minSize,
$this->minSize,
$black
);
// Now make the black circle part transparent
imagecolortransparent($mask, $black);
// Merge the two images so that only the transparent
// part shows the image and other parts become magenta solid
imagecopymerge(
$this->img,
$mask,
0,
0,
0,
0,
$this->minSize,
$this->minSize,
100
);
// Now make the magenta part transparent
// It now only keeps the center transparent(prev=black) part
// of the original image visible
imagecolortransparent($this->img, $magenta);
// Destroy the mask
imagedestroy($mask);
return $this->render();
}
public function render(): string
{
// Get the string content
// Of the generated image & return
ob_start();
imagepng($this->img);
$imagedata = ob_get_clean();
return $imagedata;
}
}
###用法:-
// First we scale the image to a smaller size, otherwise the circular crop may time out and get the string value
$image = InterventionImage::read($image)->scale(300, null)->encodeByMediaType(type: "image/png", quality: 90)->toString();
// Now simply Crop the image as a circle with our helper class
$circleImage = new CircleImage($image);
$image = $circleImage->make();
// It returns the png string image content, either convert to base64 or simply put to the storage Like below:-
// Storage: Storage::put("picture/avatar.png", $image);
// base64_encode($image);