JFIF$        dd7 

Viewing File: /home/optimaldigitaltr/public_html/src/vendor/bacon/bacon-qr-code/src/Renderer/GDLibRenderer.php

<?php

declare(strict_types=1);

namespace BaconQrCode\Renderer;

use BaconQrCode\Encoder\ByteMatrix;
use BaconQrCode\Encoder\MatrixUtil;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Exception\InvalidArgumentException;
use BaconQrCode\Exception\RuntimeException;
use BaconQrCode\Renderer\Color\Alpha;
use BaconQrCode\Renderer\Color\ColorInterface;
use BaconQrCode\Renderer\RendererStyle\EyeFill;
use BaconQrCode\Renderer\RendererStyle\Fill;
use GdImage;

final class GDLibRenderer implements RendererInterface
{
    private ?GdImage $image;

    /**
     * @var array<string, int>
     */
    private array $colors;

    public function __construct(
        private int $size,
        private int $margin = 4,
        private string $imageFormat = 'png',
        private int $compressionQuality = 9,
        private ?Fill $fill = null
    ) {
        if (! extension_loaded('gd') || ! function_exists('gd_info')) {
            throw new RuntimeException('You need to install the GD extension to use this back end');
        }

        if ($this->fill === null) {
            $this->fill = Fill::default();
        }
        if ($this->fill->hasGradientFill()) {
            throw new InvalidArgumentException('GDLibRenderer does not support gradients');
        }
    }

    /**
     * @throws InvalidArgumentException if matrix width doesn't match height
     */
    public function render(QrCode $qrCode): string
    {
        $matrix = $qrCode->getMatrix();
        $matrixSize = $matrix->getWidth();

        if ($matrixSize !== $matrix->getHeight()) {
            throw new InvalidArgumentException('Matrix must have the same width and height');
        }

        MatrixUtil::removePositionDetectionPatterns($matrix);
        $this->newImage();
        $this->draw($matrix);

        return $this->renderImage();
    }

    private function newImage(): void
    {
        $img = imagecreatetruecolor($this->size, $this->size);
        if ($img === false) {
            throw new RuntimeException('Failed to create image of that size');
        }

        $this->image = $img;
        imagealphablending($this->image, false);
        imagesavealpha($this->image, true);


        $bg = $this->getColor($this->fill->getBackgroundColor());
        imagefilledrectangle($this->image, 0, 0, $this->size, $this->size, $bg);
        imagealphablending($this->image, true);
    }

    private function draw(ByteMatrix $matrix): void
    {
        $matrixSize = $matrix->getWidth();

        $pointsOnSide = $matrix->getWidth() + $this->margin * 2;
        $pointInPx = $this->size / $pointsOnSide;

        $this->drawEye(0, 0, $pointInPx, $this->fill->getTopLeftEyeFill());
        $this->drawEye($matrixSize - 7, 0, $pointInPx, $this->fill->getTopRightEyeFill());
        $this->drawEye(0, $matrixSize - 7, $pointInPx, $this->fill->getBottomLeftEyeFill());

        $rows = $matrix->getArray()->toArray();
        $color = $this->getColor($this->fill->getForegroundColor());
        for ($y = 0; $y < $matrixSize; $y += 1) {
            for ($x = 0; $x < $matrixSize; $x += 1) {
                if (! $rows[$y][$x]) {
                    continue;
                }

                $points = $this->normalizePoints([
                    ($this->margin + $x) * $pointInPx, ($this->margin + $y) * $pointInPx,
                    ($this->margin + $x + 1) * $pointInPx, ($this->margin + $y) * $pointInPx,
                    ($this->margin + $x + 1) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
                    ($this->margin + $x) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
                ]);
                imagefilledpolygon($this->image, $points, $color);
            }
        }
    }

    private function drawEye(int $xOffset, int $yOffset, float $pointInPx, EyeFill $eyeFill): void
    {
        $internalColor = $this->getColor($eyeFill->inheritsInternalColor()
            ? $this->fill->getForegroundColor()
            : $eyeFill->getInternalColor());

        $externalColor = $this->getColor($eyeFill->inheritsExternalColor()
            ? $this->fill->getForegroundColor()
            : $eyeFill->getExternalColor());

        for ($y = 0; $y < 7; $y += 1) {
            for ($x = 0; $x < 7; $x += 1) {
                if ((($y === 1 || $y === 5) && $x > 0 && $x < 6) || (($x === 1 || $x === 5) && $y > 0 && $y < 6)) {
                    continue;
                }

                $points = $this->normalizePoints([
                    ($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
                    ($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
                    ($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
                    ($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
                ]);

                if ($y > 1 && $y < 5 && $x > 1 && $x < 5) {
                    imagefilledpolygon($this->image, $points, $internalColor);
                } else {
                    imagefilledpolygon($this->image, $points, $externalColor);
                }
            }
        }
    }

    /**
     * Normalize points will trim right and bottom line by 1 pixel.
     * Otherwise pixels of neighbors are overlapping which leads to issue with transparency and small QR codes.
     */
    private function normalizePoints(array $points): array
    {
        $maxX = $maxY = 0;
        for ($i = 0; $i < count($points); $i += 2) {
            // Do manual round as GD just removes decimal part
            $points[$i] = $newX = round($points[$i]);
            $points[$i + 1] = $newY = round($points[$i + 1]);

            $maxX = max($maxX, $newX);
            $maxY = max($maxY, $newY);
        }

        // Do trimming only if there are 4 points (8 coordinates), assumes this is square.

        for ($i = 0; $i < count($points); $i += 2) {
            $points[$i] = min($points[$i], $maxX - 1);
            $points[$i + 1] = min($points[$i + 1], $maxY - 1);
        }

        return $points;
    }

    private function renderImage(): string
    {
        ob_start();
        $quality = $this->compressionQuality;
        switch ($this->imageFormat) {
            case 'png':
                if ($quality > 9 || $quality < 0) {
                    $quality = 9;
                }
                imagepng($this->image, null, $quality);
                break;

            case 'gif':
                imagegif($this->image, null);
                break;

            case 'jpeg':
            case 'jpg':
                if ($quality > 100 || $quality < 0) {
                    $quality = 85;
                }
                imagejpeg($this->image, null, $quality);
                break;
            default:
                ob_end_clean();
                throw new InvalidArgumentException(
                    'Supported image formats are jpeg, png and gif, got: ' . $this->imageFormat
                );
        }

        imagedestroy($this->image);
        $this->colors = [];
        $this->image = null;

        return ob_get_clean();
    }

    private function getColor(ColorInterface $color): int
    {
        $alpha = 100;

        if ($color instanceof Alpha) {
            $alpha = $color->getAlpha();
            $color = $color->getBaseColor();
        }

        $rgb = $color->toRgb();

        $colorKey = sprintf('%02X%02X%02X%02X', $rgb->getRed(), $rgb->getGreen(), $rgb->getBlue(), $alpha);

        if (! isset($this->colors[$colorKey])) {
            $colorId = imagecolorallocatealpha(
                $this->image,
                $rgb->getRed(),
                $rgb->getGreen(),
                $rgb->getBlue(),
                (int)((100 - $alpha) / 100 * 127) // Alpha for GD is in range 0 (opaque) - 127 (transparent)
            );

            if ($colorId === false) {
                throw new RuntimeException('Failed to create color: #' . $colorKey);
            }

            $this->colors[$colorKey] = $colorId;
        }

        return $this->colors[$colorKey];
    }
}
Back to Directory  nL+D550H?Mx ,D"v]qv;6*Zqn)ZP0!1 A "#a$2Qr D8 a Ri[f\mIykIw0cuFcRı?lO7к_f˓[C$殷WF<_W ԣsKcëIzyQy/_LKℂ;C",pFA:/]=H  ~,ls/9ć:[=/#f;)x{ٛEQ )~ =𘙲r*2~ a _V=' kumFD}KYYC)({ *g&f`툪ry`=^cJ.I](*`wq1dđ#̩͑0;H]u搂@:~וKL Nsh}OIR*8:2 !lDJVo(3=M(zȰ+i*NAr6KnSl)!JJӁ* %݉?|D}d5:eP0R;{$X'xF@.ÊB {,WJuQɲRI;9QE琯62fT.DUJ;*cP A\ILNj!J۱+O\͔]ޒS߼Jȧc%ANolՎprULZԛerE2=XDXgVQeӓk yP7U*omQIs,K`)6\G3t?pgjrmۛجwluGtfh9uyP0D;Uڽ"OXlif$)&|ML0Zrm1[HXPlPR0'G=i2N+0e2]]9VTPO׮7h(F*癈'=QVZDF,d߬~TX G[`le69CR(!S2!P <0x<!1AQ "Raq02Br#SCTb ?Ζ"]mH5WR7k.ۛ!}Q~+yԏz|@T20S~Kek *zFf^2X*(@8r?CIuI|֓>^ExLgNUY+{.RѪ τV׸YTD I62'8Y27'\TP.6d&˦@Vqi|8-OΕ]ʔ U=TL8=;6c| !qfF3aů&~$l}'NWUs$Uk^SV:U# 6w++s&r+nڐ{@29 gL u"TÙM=6(^"7r}=6YݾlCuhquympǦ GjhsǜNlɻ}o7#S6aw4!OSrD57%|?x>L |/nD6?/8w#[)L7+6〼T ATg!%5MmZ/c-{1_Je"|^$'O&ޱմTrb$w)R$& N1EtdU3Uȉ1pM"N*(DNyd96.(jQ)X 5cQɎMyW?Q*!R>6=7)Xj5`J]e8%t!+'!1Q5 !1 AQaqё#2"0BRb?Gt^## .llQT $v,,m㵜5ubV =sY+@d{N! dnO<.-B;_wJt6;QJd.Qc%p{ 1,sNDdFHI0ГoXшe黅XۢF:)[FGXƹ/w_cMeD,ʡcc.WDtA$j@:) -# u c1<@ۗ9F)KJ-hpP]_x[qBlbpʖw q"LFGdƶ*s+ډ_Zc"?%t[IP 6J]#=ɺVvvCGsGh1 >)6|ey?Lӣm,4GWUi`]uJVoVDG< SB6ϏQ@ TiUlyOU0kfV~~}SZ@*WUUi##; s/[=!7}"WN]'(L! ~y5g9T̅JkbM' +s:S +B)v@Mj e Cf jE 0Y\QnzG1д~Wo{T9?`Rmyhsy3!HAD]mc1~2LSu7xT;j$`}4->L#vzŏILS ֭T{rjGKC;bpU=-`BsK.SFw4Mq]ZdHS0)tLg