153 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
declare(strict_types = 1);
 | 
						|
 | 
						|
namespace BaconQrCode\Renderer;
 | 
						|
 | 
						|
use BaconQrCode\Encoder\MatrixUtil;
 | 
						|
use BaconQrCode\Encoder\QrCode;
 | 
						|
use BaconQrCode\Exception\InvalidArgumentException;
 | 
						|
use BaconQrCode\Renderer\Image\ImageBackEndInterface;
 | 
						|
use BaconQrCode\Renderer\Path\Path;
 | 
						|
use BaconQrCode\Renderer\RendererStyle\EyeFill;
 | 
						|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
 | 
						|
 | 
						|
final class ImageRenderer implements RendererInterface
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var RendererStyle
 | 
						|
     */
 | 
						|
    private $rendererStyle;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var ImageBackEndInterface
 | 
						|
     */
 | 
						|
    private $imageBackEnd;
 | 
						|
 | 
						|
    public function __construct(RendererStyle $rendererStyle, ImageBackEndInterface $imageBackEnd)
 | 
						|
    {
 | 
						|
        $this->rendererStyle = $rendererStyle;
 | 
						|
        $this->imageBackEnd = $imageBackEnd;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @throws InvalidArgumentException if matrix width doesn't match height
 | 
						|
     */
 | 
						|
    public function render(QrCode $qrCode) : string
 | 
						|
    {
 | 
						|
        $size = $this->rendererStyle->getSize();
 | 
						|
        $margin = $this->rendererStyle->getMargin();
 | 
						|
        $matrix = $qrCode->getMatrix();
 | 
						|
        $matrixSize = $matrix->getWidth();
 | 
						|
 | 
						|
        if ($matrixSize !== $matrix->getHeight()) {
 | 
						|
            throw new InvalidArgumentException('Matrix must have the same width and height');
 | 
						|
        }
 | 
						|
 | 
						|
        $totalSize = $matrixSize + ($margin * 2);
 | 
						|
        $moduleSize = $size / $totalSize;
 | 
						|
        $fill = $this->rendererStyle->getFill();
 | 
						|
 | 
						|
        $this->imageBackEnd->new($size, $fill->getBackgroundColor());
 | 
						|
        $this->imageBackEnd->scale((float) $moduleSize);
 | 
						|
        $this->imageBackEnd->translate((float) $margin, (float) $margin);
 | 
						|
 | 
						|
        $module = $this->rendererStyle->getModule();
 | 
						|
        $moduleMatrix = clone $matrix;
 | 
						|
        MatrixUtil::removePositionDetectionPatterns($moduleMatrix);
 | 
						|
        $modulePath = $this->drawEyes($matrixSize, $module->createPath($moduleMatrix));
 | 
						|
 | 
						|
        if ($fill->hasGradientFill()) {
 | 
						|
            $this->imageBackEnd->drawPathWithGradient(
 | 
						|
                $modulePath,
 | 
						|
                $fill->getForegroundGradient(),
 | 
						|
                0,
 | 
						|
                0,
 | 
						|
                $matrixSize,
 | 
						|
                $matrixSize
 | 
						|
            );
 | 
						|
        } else {
 | 
						|
            $this->imageBackEnd->drawPathWithColor($modulePath, $fill->getForegroundColor());
 | 
						|
        }
 | 
						|
 | 
						|
        return $this->imageBackEnd->done();
 | 
						|
    }
 | 
						|
 | 
						|
    private function drawEyes(int $matrixSize, Path $modulePath) : Path
 | 
						|
    {
 | 
						|
        $fill = $this->rendererStyle->getFill();
 | 
						|
 | 
						|
        $eye = $this->rendererStyle->getEye();
 | 
						|
        $externalPath = $eye->getExternalPath();
 | 
						|
        $internalPath = $eye->getInternalPath();
 | 
						|
 | 
						|
        $modulePath = $this->drawEye(
 | 
						|
            $externalPath,
 | 
						|
            $internalPath,
 | 
						|
            $fill->getTopLeftEyeFill(),
 | 
						|
            3.5,
 | 
						|
            3.5,
 | 
						|
            0,
 | 
						|
            $modulePath
 | 
						|
        );
 | 
						|
        $modulePath = $this->drawEye(
 | 
						|
            $externalPath,
 | 
						|
            $internalPath,
 | 
						|
            $fill->getTopRightEyeFill(),
 | 
						|
            $matrixSize - 3.5,
 | 
						|
            3.5,
 | 
						|
            90,
 | 
						|
            $modulePath
 | 
						|
        );
 | 
						|
        $modulePath = $this->drawEye(
 | 
						|
            $externalPath,
 | 
						|
            $internalPath,
 | 
						|
            $fill->getBottomLeftEyeFill(),
 | 
						|
            3.5,
 | 
						|
            $matrixSize - 3.5,
 | 
						|
            -90,
 | 
						|
            $modulePath
 | 
						|
        );
 | 
						|
 | 
						|
        return $modulePath;
 | 
						|
    }
 | 
						|
 | 
						|
    private function drawEye(
 | 
						|
        Path $externalPath,
 | 
						|
        Path $internalPath,
 | 
						|
        EyeFill $fill,
 | 
						|
        float $xTranslation,
 | 
						|
        float $yTranslation,
 | 
						|
        int $rotation,
 | 
						|
        Path $modulePath
 | 
						|
    ) : Path {
 | 
						|
        if ($fill->inheritsBothColors()) {
 | 
						|
            return $modulePath
 | 
						|
                ->append($externalPath->translate($xTranslation, $yTranslation))
 | 
						|
                ->append($internalPath->translate($xTranslation, $yTranslation));
 | 
						|
        }
 | 
						|
 | 
						|
        $this->imageBackEnd->push();
 | 
						|
        $this->imageBackEnd->translate($xTranslation, $yTranslation);
 | 
						|
 | 
						|
        if (0 !== $rotation) {
 | 
						|
            $this->imageBackEnd->rotate($rotation);
 | 
						|
        }
 | 
						|
 | 
						|
        if ($fill->inheritsExternalColor()) {
 | 
						|
            $modulePath = $modulePath->append($externalPath->translate($xTranslation, $yTranslation));
 | 
						|
        } else {
 | 
						|
            $this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor());
 | 
						|
        }
 | 
						|
 | 
						|
        if ($fill->inheritsInternalColor()) {
 | 
						|
            $modulePath = $modulePath->append($internalPath->translate($xTranslation, $yTranslation));
 | 
						|
        } else {
 | 
						|
            $this->imageBackEnd->drawPathWithColor($internalPath, $fill->getInternalColor());
 | 
						|
        }
 | 
						|
 | 
						|
        $this->imageBackEnd->pop();
 | 
						|
 | 
						|
        return $modulePath;
 | 
						|
    }
 | 
						|
}
 |