Add captcha image generation functionality.
This commit is contained in:
117
app/Captcha/Images/Body.php
Normal file
117
app/Captcha/Images/Body.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Captcha\Images;
|
||||
|
||||
use App\Captcha\Config\ImageBody as ImageBodyConfig;
|
||||
use App\Captcha\Contracts\ImageLines;
|
||||
use App\Captcha\Dto\Coordinators;
|
||||
use App\Captcha\Dto\Image as ImageDto;
|
||||
use App\Captcha\Dto\ImageBody as ImageBodyDto;
|
||||
use App\Captcha\Dto\Sector;
|
||||
use App\Captcha\Dto\Sectors;
|
||||
use App\Captcha\Dto\Symbols;
|
||||
use App\Captcha\Contracts\ImageBody;
|
||||
use App\Captcha\Enums\SymbolType;
|
||||
use App\Captcha\Contracts\ImageManager;
|
||||
|
||||
final class Body implements ImageBody
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ImageManager $imageManager,
|
||||
private readonly ImageLines $imageLines
|
||||
) { }
|
||||
|
||||
public function processing(Symbols $symbols, ImageBodyConfig $config): ImageBodyDto
|
||||
{
|
||||
$image = $this->imageManager->createImage($config->getWidth(), $config->getHeight());
|
||||
$image->insertBackground($config->randomBackground());
|
||||
|
||||
$imageData = match ($symbols->getType()) {
|
||||
SymbolType::String => $this->processingString($image, $symbols, $config),
|
||||
};
|
||||
$image = $imageData['image'];
|
||||
|
||||
if ($config->getNumberLines() > 0) {
|
||||
$this->imageLines->processing(image: $image, colors: $config->getLineColors(), lines: $config->getNumberLines());
|
||||
}
|
||||
|
||||
$image = new ImageDto(
|
||||
imageBase64: $image->encode(),
|
||||
width: $image->getWidth(),
|
||||
height: $image->getHeight()
|
||||
);
|
||||
|
||||
return new ImageBodyDto(
|
||||
image: $image,
|
||||
coordinators: $imageData['coordinators']
|
||||
);
|
||||
}
|
||||
|
||||
private function processingString(Image $image, Symbols $symbols, ImageBodyConfig $config): array
|
||||
{
|
||||
$sectors = $this->calculateSectors($symbols, $image->getWidth(), $image->getHeight());
|
||||
$coordinators = [];
|
||||
foreach ($symbols->getSuccess() as $number => $symbol) {
|
||||
$coordinators[] = $this->processingStringSymbol($image, $symbol, $config, $sectors->random());
|
||||
}
|
||||
|
||||
if (!empty($symbols->getFakes())) {
|
||||
foreach ($symbols->getFakes() as $number => $symbol) {
|
||||
$this->processingStringSymbol($image, $symbol, $config, $sectors->random());
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'image' => $image,
|
||||
'coordinators' => $coordinators
|
||||
];
|
||||
}
|
||||
|
||||
private function processingStringSymbol(Image &$image, string|int $symbol, ImageBodyConfig $config, Sector $sector): Coordinators
|
||||
{
|
||||
$fontSize = $config->fontSize();
|
||||
if ($fontSize > $sector->getHeight()) {
|
||||
$fontSize = $sector->getHeight();
|
||||
}
|
||||
$fontPathFile = $config->randomFont();
|
||||
$fontColor = $config->randomFontColor();
|
||||
$angle = $config->randomAngle();
|
||||
$marginLeft = mt_rand($sector->getX(), $sector->getX() + $sector->getWidth() - $fontSize);
|
||||
$marginTop = mt_rand($sector->getY(), $sector->getY() + $sector->getHeight() - $fontSize);
|
||||
|
||||
return $image->addText(
|
||||
text: $symbol,
|
||||
x: $marginLeft,
|
||||
y: $marginTop,
|
||||
size: $fontSize,
|
||||
angle: $angle,
|
||||
hexColor: $fontColor,
|
||||
fontName: $fontPathFile
|
||||
);
|
||||
}
|
||||
|
||||
private function calculateSectors(Symbols $symbols, int $width, int $height): Sectors
|
||||
{
|
||||
$points = count($symbols->getSuccess()) + count($symbols->getFakes());
|
||||
$sumFloors = 3;
|
||||
$sumRooms = ceil($points / $sumFloors);
|
||||
|
||||
$heightFloor = floor($height / $sumFloors);
|
||||
$widthFloor = floor($width / $sumRooms);
|
||||
|
||||
$sectors = new Sectors();
|
||||
for ($floor = 0; $floor < $sumFloors; $floor++) {
|
||||
$y = $heightFloor * $floor;
|
||||
for ($room = 0; $room < $sumRooms; $room++) {
|
||||
$sectors->add(
|
||||
x: ($widthFloor * $room),
|
||||
y: $y,
|
||||
width: $widthFloor,
|
||||
height: $heightFloor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $sectors;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user