| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 | 
							- <?php
 
- declare(strict_types = 1);
 
- namespace BaconQrCode\Renderer\Image;
 
- use BaconQrCode\Exception\RuntimeException;
 
- use BaconQrCode\Renderer\Color\Alpha;
 
- use BaconQrCode\Renderer\Color\Cmyk;
 
- use BaconQrCode\Renderer\Color\ColorInterface;
 
- use BaconQrCode\Renderer\Color\Gray;
 
- use BaconQrCode\Renderer\Color\Rgb;
 
- use BaconQrCode\Renderer\Path\Close;
 
- use BaconQrCode\Renderer\Path\Curve;
 
- use BaconQrCode\Renderer\Path\EllipticArc;
 
- use BaconQrCode\Renderer\Path\Line;
 
- use BaconQrCode\Renderer\Path\Move;
 
- use BaconQrCode\Renderer\Path\Path;
 
- use BaconQrCode\Renderer\RendererStyle\Gradient;
 
- use BaconQrCode\Renderer\RendererStyle\GradientType;
 
- final class EpsImageBackEnd implements ImageBackEndInterface
 
- {
 
-     private const PRECISION = 3;
 
-     /**
 
-      * @var string|null
 
-      */
 
-     private $eps;
 
-     public function new(int $size, ColorInterface $backgroundColor) : void
 
-     {
 
-         $this->eps = "%!PS-Adobe-3.0 EPSF-3.0\n"
 
-             . "%%Creator: BaconQrCode\n"
 
-             . sprintf("%%%%BoundingBox: 0 0 %d %d \n", $size, $size)
 
-             . "%%BeginProlog\n"
 
-             . "save\n"
 
-             . "50 dict begin\n"
 
-             . "/q { gsave } bind def\n"
 
-             . "/Q { grestore } bind def\n"
 
-             . "/s { scale } bind def\n"
 
-             . "/t { translate } bind def\n"
 
-             . "/r { rotate } bind def\n"
 
-             . "/n { newpath } bind def\n"
 
-             . "/m { moveto } bind def\n"
 
-             . "/l { lineto } bind def\n"
 
-             . "/c { curveto } bind def\n"
 
-             . "/z { closepath } bind def\n"
 
-             . "/f { eofill } bind def\n"
 
-             . "/rgb { setrgbcolor } bind def\n"
 
-             . "/cmyk { setcmykcolor } bind def\n"
 
-             . "/gray { setgray } bind def\n"
 
-             . "%%EndProlog\n"
 
-             . "1 -1 s\n"
 
-             . sprintf("0 -%d t\n", $size);
 
-         if ($backgroundColor instanceof Alpha && 0 === $backgroundColor->getAlpha()) {
 
-             return;
 
-         }
 
-         $this->eps .= wordwrap(
 
-             '0 0 m'
 
-             . sprintf(' %s 0 l', (string) $size)
 
-             . sprintf(' %s %s l', (string) $size, (string) $size)
 
-             . sprintf(' 0 %s l', (string) $size)
 
-             . ' z'
 
-             . ' ' .$this->getColorSetString($backgroundColor) . " f\n",
 
-             75,
 
-             "\n "
 
-         );
 
-     }
 
-     public function scale(float $size) : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= sprintf("%1\$s %1\$s s\n", round($size, self::PRECISION));
 
-     }
 
-     public function translate(float $x, float $y) : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= sprintf("%s %s t\n", round($x, self::PRECISION), round($y, self::PRECISION));
 
-     }
 
-     public function rotate(int $degrees) : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= sprintf("%d r\n", $degrees);
 
-     }
 
-     public function push() : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= "q\n";
 
-     }
 
-     public function pop() : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= "Q\n";
 
-     }
 
-     public function drawPathWithColor(Path $path, ColorInterface $color) : void
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $fromX = 0;
 
-         $fromY = 0;
 
-         $this->eps .= wordwrap(
 
-             'n '
 
-             . $this->drawPathOperations($path, $fromX, $fromY)
 
-             . ' ' . $this->getColorSetString($color) . " f\n",
 
-             75,
 
-             "\n "
 
-         );
 
-     }
 
-     public function drawPathWithGradient(
 
-         Path $path,
 
-         Gradient $gradient,
 
-         float $x,
 
-         float $y,
 
-         float $width,
 
-         float $height
 
-     ) : void {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $fromX = 0;
 
-         $fromY = 0;
 
-         $this->eps .= wordwrap(
 
-             'q n ' . $this->drawPathOperations($path, $fromX, $fromY) . "\n",
 
-             75,
 
-             "\n "
 
-         );
 
-         $this->createGradientFill($gradient, $x, $y, $width, $height);
 
-     }
 
-     public function done() : string
 
-     {
 
-         if (null === $this->eps) {
 
-             throw new RuntimeException('No image has been started');
 
-         }
 
-         $this->eps .= "%%TRAILER\nend restore\n%%EOF";
 
-         $blob = $this->eps;
 
-         $this->eps = null;
 
-         return $blob;
 
-     }
 
-     private function drawPathOperations(Iterable $ops, &$fromX, &$fromY) : string
 
-     {
 
-         $pathData = [];
 
-         foreach ($ops as $op) {
 
-             switch (true) {
 
-                 case $op instanceof Move:
 
-                     $fromX = $toX = round($op->getX(), self::PRECISION);
 
-                     $fromY = $toY = round($op->getY(), self::PRECISION);
 
-                     $pathData[] = sprintf('%s %s m', $toX, $toY);
 
-                     break;
 
-                 case $op instanceof Line:
 
-                     $fromX = $toX = round($op->getX(), self::PRECISION);
 
-                     $fromY = $toY = round($op->getY(), self::PRECISION);
 
-                     $pathData[] = sprintf('%s %s l', $toX, $toY);
 
-                     break;
 
-                 case $op instanceof EllipticArc:
 
-                     $pathData[] = $this->drawPathOperations($op->toCurves($fromX, $fromY), $fromX, $fromY);
 
-                     break;
 
-                 case $op instanceof Curve:
 
-                     $x1 = round($op->getX1(), self::PRECISION);
 
-                     $y1 = round($op->getY1(), self::PRECISION);
 
-                     $x2 = round($op->getX2(), self::PRECISION);
 
-                     $y2 = round($op->getY2(), self::PRECISION);
 
-                     $fromX = $x3 = round($op->getX3(), self::PRECISION);
 
-                     $fromY = $y3 = round($op->getY3(), self::PRECISION);
 
-                     $pathData[] = sprintf('%s %s %s %s %s %s c', $x1, $y1, $x2, $y2, $x3, $y3);
 
-                     break;
 
-                 case $op instanceof Close:
 
-                     $pathData[] = 'z';
 
-                     break;
 
-                 default:
 
-                     throw new RuntimeException('Unexpected draw operation: ' . get_class($op));
 
-             }
 
-         }
 
-         return implode(' ', $pathData);
 
-     }
 
-     private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : void
 
-     {
 
-         $startColor = $gradient->getStartColor();
 
-         $endColor = $gradient->getEndColor();
 
-         if ($startColor instanceof Alpha) {
 
-             $startColor = $startColor->getBaseColor();
 
-         }
 
-         $startColorType = get_class($startColor);
 
-         if (! in_array($startColorType, [Rgb::class, Cmyk::class, Gray::class])) {
 
-             $startColorType = Cmyk::class;
 
-             $startColor = $startColor->toCmyk();
 
-         }
 
-         if (get_class($endColor) !== $startColorType) {
 
-             switch ($startColorType) {
 
-                 case Cmyk::class:
 
-                     $endColor = $endColor->toCmyk();
 
-                     break;
 
-                 case Rgb::class:
 
-                     $endColor = $endColor->toRgb();
 
-                     break;
 
-                 case Gray::class:
 
-                     $endColor = $endColor->toGray();
 
-                     break;
 
-             }
 
-         }
 
-         $this->eps .= "eoclip\n<<\n";
 
-         if ($gradient->getType() === GradientType::RADIAL()) {
 
-             $this->eps .= " /ShadingType 3\n";
 
-         } else {
 
-             $this->eps .= " /ShadingType 2\n";
 
-         }
 
-         $this->eps .= " /Extend [ true true ]\n"
 
-             . " /AntiAlias true\n";
 
-         switch ($startColorType) {
 
-             case Cmyk::class:
 
-                 $this->eps .= " /ColorSpace /DeviceCMYK\n";
 
-                 break;
 
-             case Rgb::class:
 
-                 $this->eps .= " /ColorSpace /DeviceRGB\n";
 
-                 break;
 
-             case Gray::class:
 
-                 $this->eps .= " /ColorSpace /DeviceGray\n";
 
-                 break;
 
-         }
 
-         switch ($gradient->getType()) {
 
-             case GradientType::HORIZONTAL():
 
-                 $this->eps .= sprintf(
 
-                     " /Coords [ %s %s %s %s ]\n",
 
-                     round($x, self::PRECISION),
 
-                     round($y, self::PRECISION),
 
-                     round($x + $width, self::PRECISION),
 
-                     round($y, self::PRECISION)
 
-                 );
 
-                 break;
 
-             case GradientType::VERTICAL():
 
-                 $this->eps .= sprintf(
 
-                     " /Coords [ %s %s %s %s ]\n",
 
-                     round($x, self::PRECISION),
 
-                     round($y, self::PRECISION),
 
-                     round($x, self::PRECISION),
 
-                     round($y + $height, self::PRECISION)
 
-                 );
 
-                 break;
 
-             case GradientType::DIAGONAL():
 
-                 $this->eps .= sprintf(
 
-                     " /Coords [ %s %s %s %s ]\n",
 
-                     round($x, self::PRECISION),
 
-                     round($y, self::PRECISION),
 
-                     round($x + $width, self::PRECISION),
 
-                     round($y + $height, self::PRECISION)
 
-                 );
 
-                 break;
 
-             case GradientType::INVERSE_DIAGONAL():
 
-                 $this->eps .= sprintf(
 
-                     " /Coords [ %s %s %s %s ]\n",
 
-                     round($x, self::PRECISION),
 
-                     round($y + $height, self::PRECISION),
 
-                     round($x + $width, self::PRECISION),
 
-                     round($y, self::PRECISION)
 
-                 );
 
-                 break;
 
-             case GradientType::RADIAL():
 
-                 $centerX = ($x + $width) / 2;
 
-                 $centerY = ($y + $height) / 2;
 
-                 $this->eps .= sprintf(
 
-                     " /Coords [ %s %s 0 %s %s %s ]\n",
 
-                     round($centerX, self::PRECISION),
 
-                     round($centerY, self::PRECISION),
 
-                     round($centerX, self::PRECISION),
 
-                     round($centerY, self::PRECISION),
 
-                     round(max($width, $height) / 2, self::PRECISION)
 
-                 );
 
-                 break;
 
-         }
 
-         $this->eps .= " /Function\n"
 
-             . " <<\n"
 
-             . "  /FunctionType 2\n"
 
-             . "  /Domain [ 0 1 ]\n"
 
-             . sprintf("  /C0 [ %s ]\n", $this->getColorString($startColor))
 
-             . sprintf("  /C1 [ %s ]\n", $this->getColorString($endColor))
 
-             . "  /N 1\n"
 
-             . " >>\n>>\nshfill\nQ\n";
 
-     }
 
-     private function getColorSetString(ColorInterface $color) : string
 
-     {
 
-         if ($color instanceof Rgb) {
 
-             return $this->getColorString($color) . ' rgb';
 
-         }
 
-         if ($color instanceof Cmyk) {
 
-             return $this->getColorString($color) . ' cmyk';
 
-         }
 
-         if ($color instanceof Gray) {
 
-             return $this->getColorString($color) . ' gray';
 
-         }
 
-         return $this->getColorSetString($color->toCmyk());
 
-     }
 
-     private function getColorString(ColorInterface $color) : string
 
-     {
 
-         if ($color instanceof Rgb) {
 
-             return sprintf('%s %s %s', $color->getRed() / 255, $color->getGreen() / 255, $color->getBlue() / 255);
 
-         }
 
-         if ($color instanceof Cmyk) {
 
-             return sprintf(
 
-                 '%s %s %s %s',
 
-                 $color->getCyan() / 100,
 
-                 $color->getMagenta() / 100,
 
-                 $color->getYellow() / 100,
 
-                 $color->getBlack() / 100
 
-             );
 
-         }
 
-         if ($color instanceof Gray) {
 
-             return sprintf('%s', $color->getGray() / 100);
 
-         }
 
-         return $this->getColorString($color->toCmyk());
 
-     }
 
- }
 
 
  |