This commit adds an Image interface and implementation that will be used in the Captcha generation process. The Image object includes methods for manipulating an image, such as adding text, inserting a background, and adding a line. These methods will provide the necessary functionalities for generating a Captcha.

This commit is contained in:
Leonid Nikitin 2023-06-28 17:22:19 +06:00
parent f6669e93dc
commit f2ecdfcf97
Signed by: kor-elf
GPG Key ID: 7DE8F80C5CEC2C0D
2 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,17 @@
<?php declare(strict_types=1);
namespace App\Captcha\Contracts;
use App\Captcha\Dto\Coordinators;
interface Image
{
public function __construct(int $width, int $height);
public function getWidth(): int;
public function getHeight(): int;
public function insertBackground(string $pathToFile): self;
public function addText(string $text, int $x, int $y, float $size, float $angle, string $hexColor, string $fontName): Coordinators;
public function addLine(int $x1, int $y1, int $x2, int $y2, string $hexColor): self;
public function encode(): string;
public function __destruct();
}

View File

@ -0,0 +1,138 @@
<?php declare(strict_types=1);
namespace App\Captcha\Images;
use App\Captcha\Contracts\Image as ImageContract;
use App\Captcha\Dto\Coordinators;
use App\Captcha\Exceptions\CaptchaException;
final class Image implements ImageContract
{
private readonly \GdImage $image;
public function __construct(int $width, int $height) {
$this->image = imagecreatetruecolor($width, $height);
}
public function getWidth(): int
{
return imagesx($this->image);
}
public function getHeight(): int
{
return imagesy($this->image);
}
public function insertBackground(string $pathToFile): ImageContract
{
list($backgroundWidth, $backgroundHeight) = getimagesize($pathToFile);
$background = $this->createImageFromPathToFile($pathToFile);
imagecopyresampled(
dst_image: $this->image,
src_image: $background,
dst_x: 0,
dst_y: 0,
src_x: 0,
src_y: 0,
dst_width: $this->getWidth(),
dst_height: $this->getHeight(),
src_width: $backgroundWidth,
src_height: $backgroundHeight
);
imagedestroy($background);
return $this;
}
public function addText(string $text, int $x, int $y, float $size, float $angle, string $hexColor, string $fontName): Coordinators
{
$y += intval($size);
$result = imagefttext(
image: $this->image,
size: $size,
angle: $angle,
x: $x,
y: $y,
color: $this->colorConvertHexToColorIndex($hexColor),
font_filename: $fontName,
text: $text
);
return new Coordinators(
x1: $result[0],
y1: $result[1],
x2: $result[2],
y2: $result[3],
x3: $result[4],
y3: $result[5],
x4: $result[6],
y4: $result[7]
);
}
public function addLine(int $x1, int $y1, int $x2, int $y2, string $hexColor): self
{
imageline(
image: $this->image,
x1: $x1,
y1: $y1,
x2: $x2,
y2: $y2,
color: $this->colorConvertHexToColorIndex($hexColor)
);
return $this;
}
public function encode(): string
{
ob_start();
imagealphablending($this->image, false);
imagesavealpha($this->image, true);
imagepng($this->image, null, -1);
$mime = image_type_to_mime_type(IMAGETYPE_PNG);
$buffer = ob_get_contents();
ob_end_clean();
return sprintf('data:%s;base64,%s',
$mime,
base64_encode($buffer)
);
}
public function __destruct() {
imagedestroy($this->image);
}
private function createImageFromPathToFile(string $pathToFile): \GdImage
{
return match (mime_content_type($pathToFile)) {
'image/jpeg' => imagecreatefromjpeg($pathToFile),
'image/png' => imagecreatefrompng($pathToFile),
default => throw new CaptchaException('Couldn\'t open the file. Not a valid type. File ' . $pathToFile . '.')
};
}
private function colorConvertHexToColorIndex(string $hexColor): int
{
$hexColor = str_replace('#', '', $hexColor);
if (strlen($hexColor) === 3) {
return imagecolorexact(
image: $this->image,
red: hexdec(str_repeat(substr($hexColor, 0, 1), 2)),
blue: hexdec(str_repeat(substr($hexColor, 1, 1), 2)),
green: hexdec(str_repeat(substr($hexColor, 2, 1), 2))
);
}
$colorVal = hexdec($hexColor);
return imagecolorexact(
image: $this->image,
red: 0xFF & ($colorVal >> 0x10),
blue: 0xFF & ($colorVal >> 0x8),
green: 0xFF & $colorVal
);
}
}