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=M8LxrMP f/,iTe7U%f1/&h%r9κ٠,TӃkw&^-XǺT;[ccϒ+ ۸q&^?P'ҟxn .`G5mT=Lug䄙4h5A!_F#Vg9= RL@d:K$x큫 <#GBNE)rQ+{/s(1ʳ_q}ѧC'-+r?y?@ޯ3EAwc%Ԝl"lÜ˅΄wM~`M &41V~>._7䖚Z7_T!-w(q?s8~ՄɞcQWE:S5cowA{C+`KNa r譏~9qP"Zg6/ (&Us/6qŅ5 Zֽ,ppba}y;¤-Qv7%'%d1 055rqʸٙ(j;Ci$ b̎Rq?Wꗧu?3?F4`Ҳ npS+kjN0zܣQ1 F>: ,<3.ΥۑwM5ΨHPCY5D8jE2K$؉c}2GOBIU.`oV9\@hX732`߹o pS |60zܣQ1 F>:Px7L5,c6]^# .ï䄙4h5[2_NXTn\ /EmptUW Cʽ}{uF c@T_aꦍ-Gq+9o07Cz`YP_aEҊ+yv%[hEaScK86V>ؼ*O4@\x'@|+9<2,"{ƿVZ0puQGFYԃ;GK핌&:{ר?F;XAi|+y=`߈ě}}oMiEȷh؈{\6ѻ~fhP{Ll;[#XsdV;On$rn[1 _qA OQ(",ndO&`/Qvs*nf%ei RTC/ۖP%>iSAphWa1}GV䥟;@PWDݯ-kXd| Z-Lлpûo0i/ J3~BTs~gq!&M{K S>! H`5ǵpba}y;¤-D.}sݮi4 t #`uvFŏw3_DnX;q[Y!7]qCT3$=/Q>{g}SejU=\|0l$AR)$rKfpİR\ ރTMfjK|.Eʎ'JuֆQ/׳z;tIBƞNX&Lb&ᨔTC/ۖP%>iSAphWa1}GV䥟;@PWDݯ-kXd| Z-Lлpûo0i/ J3~BTs~gq!&MαAWW:q<舗a{jʜ~ѝOQ{ͪb zXiEvѕ1WNg)Mo@ؔ'v2|,+ה@"Pe1 i=a|ҋx+vE7{&ݙnʼncvs@MfC P%#BS()L@*dFh{fwI!$渽w"ߝߑw[BHzCФ)ylMD^,+X8`u7&ɩD&D7liQ$r{#bWf0 `WI]2}0/FuZJ>Q`!wz|ϖ6w>,-T6tF0C6(豯phr%E.JfZܒët/B"ubḏ.3 CzlCB wq& 7 -ʠc Dken:J=>$Kge+L[x78(&ԀPV 5S89I_t *lb8IMDC7`XmyhvjXi}ˌIi%ց@UO8c~G BƣȚvó?oCId$E}gF@>K7EdڐSxb貎fҔ}HoX;q[Y!7]qCT3$=/Q>{g}SejU=\|0l$AR)$rKfpİR\ ރTMfjK|.Eʎ'JuֆQ/܈tzSzMgONF_r D QW)>V4&=.w7vTƐ( qf2dުD縷{C!ާ" ?+\ߢS;" <,Rjȿb8n{!x@njM큫 <#GBNVnP~$W:)Fnjruӎ n1]rIo,E| ^uy9TOZ-t[<syAʿ5L溩Q`!uJ ]9{f;l(vG/#әZ)F&Cim"y*H5E r;c0Pn.*hMD {e=xmӀg5̺U5hڴ5i͓&`GJJ0eU}r8{uYkBZr $gradient, float $x, float $y, float $width, float $height ) : void { if (null === $this->draw) { throw new RuntimeException('No image has been started'); } $this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height)); $this->drawPath($path); } public function done() : string { if (null === $this->draw) { throw new RuntimeException('No image has been started'); } $this->image->drawImage($this->draw); $blob = $this->image->getImageBlob(); $this->draw->clear(); $this->image->clear(); $this->draw = null; $this->image = null; $this->gradientCount = null; return $blob; } private function drawPath(Path $path) : void { $this->draw->pathStart(); foreach ($path as $op) { switch (true) { case $op instanceof Move: $this->draw->pathMoveToAbsolute($op->getX(), $op->getY()); break; case $op instanceof Line: $this->draw->pathLineToAbsolute($op->getX(), $op->getY()); break; case $op instanceof EllipticArc: $this->draw->pathEllipticArcAbsolute( $op->getXRadius(), $op->getYRadius(), $op->getXAxisAngle(), $op->isLargeArc(), $op->isSweep(), $op->getX(), $op->getY() ); break; case $op instanceof Curve: $this->draw->pathCurveToAbsolute( $op->getX1(), $op->getY1(), $op->getX2(), $op->getY2(), $op->getX3(), $op->getY3() ); break; case $op instanceof Close: $this->draw->pathClose(); break; default: throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); } } $this->draw->pathFinish(); } private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string { list($width, $height) = $this->matrices[$this->matrixIndex]->apply($width, $height); $startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString(); $endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString(); $gradientImage = new Imagick(); switch ($gradient->getType()) { case GradientType::HORIZONTAL(): $gradientImage->newPseudoImage((int) $height, (int) $width, sprintf( 'gradient:%s-%s', $startColor, $endColor )); $gradientImage->rotateImage('transparent', -90); break; case GradientType::VERTICAL(): $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( 'gradient:%s-%s', $startColor, $endColor )); break; case GradientType::DIAGONAL(): case GradientType::INVERSE_DIAGONAL(): $gradientImage->newPseudoImage((int) ($width * sqrt(2)), (int) ($height * sqrt(2)), sprintf( 'gradient:%s-%s', $startColor, $endColor )); if (GradientType::DIAGONAL() === $gradient->getType()) { $gradientImage->rotateImage('transparent', -45); } else { $gradientImage->rotateImage('transparent', -135); } $rotatedWidth = $gradientImage->getImageWidth(); $rotatedHeight = $gradientImage->getImageHeight(); $gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0); $gradientImage->cropImage( intdiv($rotatedWidth, 2) - 2, intdiv($rotatedHeight, 2) - 2, intdiv($rotatedWidth, 4) + 1, intdiv($rotatedWidth, 4) + 1 ); break; case GradientType::RADIAL(): $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( 'radial-gradient:%s-%s', $startColor, $endColor )); break; } $id = sprintf('g%d', ++$this->gradientCount); $this->draw->pushPattern($id, 0, 0, $width, $height); $this->draw->composite(Imagick::COMPOSITE_COPY, 0, 0, $width, $height, $gradientImage); $this->draw->popPattern(); return $id; } private function getColorPixel(ColorInterface $color) : ImagickPixel { $alpha = 100; if ($color instanceof Alpha) { $alpha = $color->getAlpha(); $color = $color->getBaseColor(); } if ($color instanceof Rgb) { return new ImagickPixel(sprintf( 'rgba(%d, %d, %d, %F)', $color->getRed(), $color->getGreen(), $color->getBlue(), $alpha / 100 )); } if ($color instanceof Cmyk) { return new ImagickPixel(sprintf( 'cmyka(%d, %d, %d, %d, %F)', $color->getCyan(), $color->getMagenta(), $color->getYellow(), $color->getBlack(), $alpha / 100 )); } if ($color instanceof Gray) { return new ImagickPixel(sprintf( 'graya(%d%%, %F)', $color->getGray(), $alpha / 100 )); } return $this->getColorPixel(new Alpha($alpha, $color->toRgb())); } }