6TF9鱈o3GwY9"rwU7oSXȯImPӄf;2^vEgB=f}-qIz>r*YӼJp EX%0 {kZu4WP2Ӕ,] UXץa&eQ3T N%Ea %dEC;ӻI s-]EB*^tVMp/F1uLr4WB&T%{6d%EB XqVƬy4NJ)ʖIE*7oSXȯ)j+>`Ʀ7=M@;Ħ:eQ_sMO0>#U0/zoNޯ /J.hGhM@;Ħ:e&]bv^%hwigCt汾|IN52fo3~nP$[fJۍJ1DZ;CTNt/S16 Wòm#|`eVnh1BwK=E;4\kzG¼N=ci>CΩD%{Լ7JX;ܕ`G Nqm+8nx*5\޲77! I7r٦'{ntp"J 8Q⵨|lO4cLS78:^x'Pu[*$S78:^x H ~z.GM `?#' 1ߎz0xaZ=]$'Vh8^hLRxZq3.eV2K!2 YM:2&L{N)pCq7KQiMe2-$jn-./Xz2; 0I;m:}l`*5:(Iт=go0Yı( KRZ^iHގb >H]9c:sPlap$\/k"mnMDydz\z(KjU4C}{󚵎C2$J@8"{5tjUNM߫+hUj`V(Ex #p-%2ZRhrqgP p !ӱ2{oTځٲ>xsy^T2YK9*M"<ˬ83:8KH}T-?pɾ@<3wޑ"r5rR֔ I1zM?^%g'W/^2,"{ƿVZ0puQGFYԃ;GK핌&:{ר?F;Xb! oʹkߔ'-+r?y?@ޯ3EAwc%&I=[68"_1< XqO"n#E>޲R![ھoWÙDHu:|NC:Ə8]?GNC/0߶VrK7EdڐSxYjI dkO̗m|G~/B"ubḏ.3 CgU4~Xv.P2E`$zEFe4Vlo $upqYw_t JմN(@v΄VK$dS0w{1r00~l ^r'Gre>泂=ژ~ѝOQ{ͪb zXiEvѕ1WNg)Mo@ؔ'v2|,+ה@D$ G'THqQOH8%(bF7p,eS.seSk2qt sIBETMfa/B|%WzbVowLhwxPNnG^K7EdڐSxMz@[\*@oLu Tf#] Oujኲh9镟i;?ejU=\|0l$AR)$rKfpİR\ ރTMfjK|.Eʎ'JuֆQ/Ǡ98aZUa@:dq Mw؄F}J~s+<:*A-2ҽ6kv[](&T@MrtL_Z Eȷh؈{\6ѻ~fhP{Ll;[#XsdV;On$rn[1 _qA OQ(",ndO&}`. $-uţW~ѝOQ{ͪb z sS=VW Wzǝ(KDH"(9fhTDlzda&P@ؔ'v2|,+ה@D$ G'THqQOH8%(bF7p,eS.seSk2qt sIBETMfa  b({AX쑂0i>d/Kw(Vzmݟ +_OKWV}iGݏpɾ@<3wޑ"r5rR֔ I1zM?^%g'W/^2,"{ƿVZ0pu&D ,$K0awE3vm'K&#?tC#+PUs+z~06iLTsGbnO#XC>ؗ2pu 7gi:x<gXx6K§ Wp0c:toԿoid { 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()); } }