118 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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;
 | 
						|
    }
 | 
						|
}
 |