begin process at 2008 05 16 04:29:56
1 173 209 membres
51 nouveaux aujourd'hui
13 970 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

[PHP5] PHPDRAW - LE PHOTOSHOP DE PHP (OU PRESQUE...)


Information sur la source

Catégorie :Class et Objet ( POO ) Classé sous : image, ajax, interpreter, logo, fun Niveau : Expert Date de création : 07/10/2007 Date de mise à jour : 01/01/2008 10:16:34 Vu / téléchargé: 4 090 / 182

Note :
9 / 10 - par 1 personne
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (35)
Ajouter un commentaire et/ou une note

Description

Hello,

bon, ce code ne sert pas à grand chose, c'est un amusement. Etant donné que je ne parviens pas à uploader la 3ème partie de mon tuto sur les design patterns, je me suis amusé à approfondir le dernier exemple de ce tuto sur le design pattern INTERPRETER.
Ce code est une petite interface en Ajax permettant de générer une image grâce à des commandes simples : right 50 tracera un trait de 50 pixels vers la droite. On peut les enchaîner:
right 50 down 20 right 60 up 50
Les possibilités sont :
right, left, up, down suivis chacun d'un entier en pixel pour tracer.
pixel suivi d'un entier en pixel pour l'épaisseur du trait.
color suivi d'un entier à 9 chiffres (rrrgggbbb) pour la couleur du trait.
x, y suivis chacun d'un entier en pixel pour la position x ou y.
file suivi d'un nom de fichier pour sauvegarder votre oeuvre d'art ;-)

Une doc est incluse.

Ce code n'a aucune prétention, c'est juste pour le fun. Mais il a des vertus pédagogiques certaines...!

NB:
Ce code utilise la librairie js protoype pour faciliter le code js.
Ce code n'ea été testé QUE sous Firefox, et je doute qu'il tourne sous IE à cause de la récupération des textNode du flux xml (pas eu le temps de tester sous IE pour être franc).

Source

  • <?php
  • /**
  • * Notre INTERFACE EXPRESSION
  • *
  • */
  • interface expression {
  • public static function interpret(interpreter $subject, $mParam);
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour les mouvements vers la droite
  • *
  • */
  • class right implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X+$mParam, $subject->Y, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
  • }
  • $subject->X += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour les mouvements vers la gauche
  • *
  • */
  • class left implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X-$mParam, $subject->Y, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
  • }
  • $subject->X -= $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour les mouvements vers le haut
  • *
  • */
  • class up implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y-$mParam, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
  • }
  • $subject->Y -= $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour les mouvements vers le bas
  • *
  • */
  • class down implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y+$mParam, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la création d'une ellipse
  • *
  • */
  • class ellipse implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(false === strpos($mParam, '-')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
  • }
  • $aParam = explode('-', $mParam);
  • $iWidth = (int)$aParam[0];
  • $iHeight = (int)$aParam[1];
  • if (false === imageellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create ellipse');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la création d'une ellipse remplie
  • *
  • */
  • class filledellipse implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(false === strpos($mParam, '-')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
  • }
  • $aParam = explode('-', $mParam);
  • $iWidth = (int)$aParam[0];
  • $iHeight = (int)$aParam[1];
  • if (false === imagefilledellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create filled ellipse');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la création d'un arc remplis
  • *
  • */
  • class filledarc implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(false === strpos($mParam, '-')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
  • }
  • $aParam = explode('-', $mParam);
  • $iWidth = (int)$aParam[0];
  • $iHeight = (int)$aParam[1];
  • $iStart = (int)$aParam[2];
  • $iEnd = (int)$aParam[3];
  • if (false === imagefilledarc($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $iStart, $iEnd, $subject->RCOLOR, IMG_ARC_PIE)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create filled arc');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la création d'un rectangle
  • *
  • */
  • class rectangle implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(false === strpos($mParam, '-')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
  • }
  • $aParam = explode('-', $mParam);
  • $iX = (int)$aParam[0];
  • $iY = (int)$aParam[1];
  • if (false === imagerectangle($subject->IMG, $subject->X, $subject->Y, $iX, $iY, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create rectangle');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la création d'un polygone
  • *
  • */
  • class polygon implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(false === strpos($mParam, '-')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
  • }
  • $aParam = array_map ('intval', explode('-', $mParam));
  • $iCount = count($aParam);
  • if(0 !== $iCount%2) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : total points must be even : '.$iCount);
  • }
  • $iCount /= 2;
  • if (false === imagepolygon($subject->IMG, $aParam, $iCount, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create polygon');
  • }
  • $subject->Y += $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la couleur du trait
  • *
  • */
  • class color implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam) || 9 !== strlen($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid color '.$mParam);
  • }
  • $iRed = (int)substr($mParam, 0, 3);
  • $iGreen = (int)substr($mParam, 3, 3);
  • $iBlue = (int)substr($mParam, 6, 3);
  • $subject->RCOLOR = imagecolorallocate($subject->IMG, $iRed, $iGreen, $iBlue);
  • $subject->SCOLOR = $mParam;
  • if(false === $subject->RCOLOR) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to allocate color '.$mParam);
  • }
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la position X
  • *
  • */
  • class x implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • $subject->X = $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la position Y
  • *
  • */
  • class y implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • $subject->Y = $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour l'épaisseur du trait
  • *
  • */
  • class pixel implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • if (false === imagesetthickness($subject->IMG, $mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to set thickness '.$mParam);
  • }
  • $subject->SPIXEL = $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour initialiser la taille de la police de caractère (1-5)
  • *
  • */
  • class fontsize implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_numeric($mParam) || $mParam < 1 || $mParam > 5) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid font size '.$mParam);
  • }
  • $mParam = (int)$mParam;
  • $subject->FONTSIZE = $mParam;
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour l'écriture d'un texte
  • *
  • */
  • class text implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(0 !== strpos($mParam, '"') || (strlen($mParam) - 1) !== strrpos($mParam, '"')) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid text value '.$mParam);
  • }
  • $mParam = trim($mParam, '"');
  • if (false === imagestring($subject->IMG, $subject->FONTSIZE, $subject->X, $subject->Y, $mParam, $subject->RCOLOR)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to write text '.$mParam);
  • }
  • }
  • }
  • /**
  • * Une EXPRESSION CONCRETE pour la sauvegarde de l'image sous un nom particulier
  • *
  • */
  • class file implements expression {
  • public static function interpret(interpreter $subject, $mParam) {
  • if(!is_string($mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid filename '.$mParam);
  • }
  • if (false === imagepng($subject->IMG, $mParam)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to ssave image to file '.$mParam);
  • }
  • }
  • }
  • /**
  • * Notre INTERPRETER
  • *
  • */
  • class interpreter {
  • private $iX = 200;
  • private $iY = 200;
  • private $sColor;
  • private $iWidth = 500;
  • private $iHeight = 500;
  • private $iThickNess = 1;
  • private $iFontSize = 1;
  • private $aDefaultDim = array(500,500);
  • private $oExpressionStack;
  • private $imh;
  • private $colorh;
  • private $aCor = array(
  • 'X' => array('cor' => 'iX', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'Y' => array('cor' => 'iY', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'COLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
  • 'SCOLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
  • 'RCOLOR' => array('cor' => 'colorh', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'WIDTH' => array('cor' => 'iWidth', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'HEIGHT' => array('cor' => 'iHeight', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'PIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'FONTSIZE' => array('cor' => 'iFontSize', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'SPIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
  • 'IMG' => array('cor' => 'imh', 'type' => 'is_resource', 'gettable' => true, 'settable' => false)
  • );
  • public function __construct($sFile = null) {
  • if(!is_null($sFile)) {
  • $this->imh = @imagecreatefrompng($sFile);
  • if(!$this->imh) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : '.$sFile.' has not been found');
  • }
  • } else {
  • $this->imh = imagecreatetruecolor($this->iWidth, $this->iHeight);
  • imagecolorallocate($this->imh, 0, 0, 0);
  • }
  • }
  • public function interpret ($sChaine) {
  • if(!is_string($sChaine)) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Parameter must be a string');
  • }
  • $this->oExpressionStack = new ArrayIterator(preg_split('`("[^"]+")|[\s]+`', $sChaine, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE));
  • $this->evaluate();
  • }
  • private function evaluate() {
  • while($this->oExpressionStack->valid()) {
  • $sToken = $this->oExpressionStack->current();
  • if(!class_exists($sToken)) {
  • throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid expression '.$sToken);
  • }
  • $this->oExpressionStack->next();
  • $mParam = $this->oExpressionStack->current();
  • $interpreter = new ReflectionMethod($sToken, 'interpret');
  • $interpreter->invoke(null, $this, $mParam);
  • $this->oExpressionStack->next();
  • }
  • }
  • public function getMove() {
  • if(true === headers_sent()) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Unable to display image, headers already sent');
  • }
  • header('Content-type: image/png');
  • imagepng($this->imh);
  • }
  • public function getSavedMove($sFile) {
  • imagepng($this->imh, $sFile);
  • }
  • public function __get($sProp) {
  • if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['gettable']) || false === $this->aCor[$sProp]['gettable']) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not gettable');
  • }
  • $sThisProp = $this->aCor[$sProp]['cor'];
  • return $this->$sThisProp;
  • }
  • public function __set($sProp, $mVal) {
  • if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['settable']) || false === $this->aCor[$sProp]['settable'] || !isset($this->aCor[$sProp]['type'])) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not settable');
  • }
  • $sFunc = $this->aCor[$sProp]['type'];
  • if(!$sFunc($mVal)) {
  • throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Value '.$mVal.' is not a valid value for '.$sProp.'; waited : '.substr($sFunc, 3));
  • }
  • if($sProp === 'COLOR') {
  • color::interpret($this, $mVal);
  • $this->sColor = $mVal;
  • } elseif($sProp === 'PIXEL') {
  • pixel::interpret($this, $mVal);
  • $this->iThickNess = (int)$mVal;
  • } elseif($sProp === 'FONTSIZE') {
  • fontsize::interpret($this, $mVal);
  • $this->iFontSize = (int)$mVal;
  • } else {
  • $sThisProp = $this->aCor[$sProp]['cor'];
  • $this->$sThisProp = $mVal;
  • }
  • }
  • }
  • ?>
<?php
/**
 * Notre INTERFACE EXPRESSION
 *
 */
interface expression {
	public static function interpret(interpreter $subject, $mParam);
}

/**
 * Une EXPRESSION CONCRETE pour les mouvements vers la droite
 *
 */
class right implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
		}
		$mParam = (int)$mParam;
		if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X+$mParam, $subject->Y, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
		}
		$subject->X += $mParam;
	}
}

/**
 * Une EXPRESSION CONCRETE pour les mouvements vers la gauche
 *
 */
class left implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
		}
		$mParam = (int)$mParam;
		if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X-$mParam, $subject->Y, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
		}
		$subject->X -= $mParam;
	}
}

/**
 * Une EXPRESSION CONCRETE pour les mouvements vers le haut
 *
 */
class up implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
		}
		$mParam = (int)$mParam;
		if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y-$mParam, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
		}
		$subject->Y -= $mParam;
	}
}

/**
 * Une EXPRESSION CONCRETE pour les mouvements vers le bas
 *
 */
class down implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
		}
		$mParam = (int)$mParam;		
		if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y+$mParam, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
		}
		$subject->Y += $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la création d'une ellipse
 *
 */
class ellipse implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(false === strpos($mParam, '-')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
		}
		$aParam = explode('-', $mParam);
		$iWidth = (int)$aParam[0];
		$iHeight = (int)$aParam[1];		
		if (false === imageellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create ellipse');
		}
		$subject->Y += $mParam;
	}	
}

/**
* Une EXPRESSION CONCRETE pour la création d'une ellipse remplie
*
*/
class filledellipse implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(false === strpos($mParam, '-')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
		}
		$aParam = explode('-', $mParam);
		$iWidth = (int)$aParam[0];
		$iHeight = (int)$aParam[1];
		if (false === imagefilledellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create filled ellipse');
		}
		$subject->Y += $mParam;
	}
}

/**
* Une EXPRESSION CONCRETE pour la création d'un arc remplis
*
*/
class filledarc implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(false === strpos($mParam, '-')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
		}
		$aParam = explode('-', $mParam);
		$iWidth = (int)$aParam[0];
		$iHeight = (int)$aParam[1];
		$iStart = (int)$aParam[2];
		$iEnd = (int)$aParam[3];
		if (false === imagefilledarc($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $iStart, $iEnd, $subject->RCOLOR, IMG_ARC_PIE)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create filled arc');
		}
		$subject->Y += $mParam;
	}
}

/**
 * Une EXPRESSION CONCRETE pour la création d'un rectangle
 *
 */
class rectangle implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(false === strpos($mParam, '-')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
		}
		$aParam = explode('-', $mParam);
		$iX = (int)$aParam[0];
		$iY = (int)$aParam[1];		
		if (false === imagerectangle($subject->IMG, $subject->X, $subject->Y, $iX, $iY, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create rectangle');
		}
		$subject->Y += $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la création d'un polygone
 *
 */
class polygon implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(false === strpos($mParam, '-')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
		}
		$aParam = array_map ('intval', explode('-', $mParam));
		$iCount = count($aParam);
		if(0 !== $iCount%2) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : total points must be even : '.$iCount);
		}
		$iCount /= 2;
		if (false === imagepolygon($subject->IMG, $aParam, $iCount, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create polygon');
		}
		$subject->Y += $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la couleur du trait
 *
 */
class color implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam) || 9 !== strlen($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid color '.$mParam);
		}
		$iRed = (int)substr($mParam, 0, 3);
		$iGreen = (int)substr($mParam, 3, 3);
		$iBlue = (int)substr($mParam, 6, 3);
		$subject->RCOLOR = imagecolorallocate($subject->IMG, $iRed, $iGreen, $iBlue);
		$subject->SCOLOR = $mParam;
		if(false === $subject->RCOLOR) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to allocate color '.$mParam);
		}
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la position X
 *
 */
class x implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
		}
		$mParam = (int)$mParam;
		$subject->X = $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la position Y
 *
 */
class y implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
		}
		$mParam = (int)$mParam;
		$subject->Y = $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour l'épaisseur du trait
 *
 */
class pixel implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
		}
		$mParam = (int)$mParam;
		if (false === imagesetthickness($subject->IMG, $mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to set thickness '.$mParam);
		}
		$subject->SPIXEL = $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour initialiser la taille de la police de caractère (1-5)
 *
 */
class fontsize implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_numeric($mParam) || $mParam < 1 || $mParam > 5) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid font size '.$mParam);
		}
		$mParam = (int)$mParam;
		$subject->FONTSIZE = $mParam;
	}	
}

/**
 * Une EXPRESSION CONCRETE pour l'écriture d'un texte
 *
 */
class text implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(0 !== strpos($mParam, '"') || (strlen($mParam) - 1) !== strrpos($mParam, '"')) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid text value '.$mParam);
		}
		$mParam = trim($mParam, '"');
		if (false === imagestring($subject->IMG, $subject->FONTSIZE, $subject->X, $subject->Y, $mParam, $subject->RCOLOR)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to write text '.$mParam);
		}
	}	
}

/**
 * Une EXPRESSION CONCRETE pour la sauvegarde de l'image sous un nom particulier
 *
 */
class file implements expression {
	public static function interpret(interpreter $subject, $mParam) {
		if(!is_string($mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid filename '.$mParam);
		}
		if (false === imagepng($subject->IMG, $mParam)) {
			throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to ssave image to file '.$mParam);
		}
	}	
}

/**
 * Notre INTERPRETER
 *
 */
class interpreter {
	private $iX = 200;
	private $iY = 200;
	private $sColor;
	private $iWidth = 500;
	private $iHeight = 500;
	private $iThickNess = 1;
	private $iFontSize = 1;
	private $aDefaultDim = array(500,500);
	private $oExpressionStack;
	private $imh;
	private $colorh;
	
	private $aCor = array(
		'X' => array('cor' => 'iX', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'Y' => array('cor' => 'iY', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'COLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
		'SCOLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
		'RCOLOR' => array('cor' => 'colorh', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'WIDTH' => array('cor' => 'iWidth', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'HEIGHT' => array('cor' => 'iHeight', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'PIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'FONTSIZE' => array('cor' => 'iFontSize', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'SPIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
		'IMG' => array('cor' => 'imh', 'type' => 'is_resource', 'gettable' => true, 'settable' => false)
	);
	
	public function __construct($sFile = null) {
		if(!is_null($sFile)) {
			$this->imh = @imagecreatefrompng($sFile);
			if(!$this->imh) {
				throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : '.$sFile.' has not been found');
			}
		} else {
			$this->imh = imagecreatetruecolor($this->iWidth, $this->iHeight);
			imagecolorallocate($this->imh, 0, 0, 0);
		}
	}
	
	public function interpret ($sChaine) {
		if(!is_string($sChaine)) {
			throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Parameter must be a string');
		}
		$this->oExpressionStack = new ArrayIterator(preg_split('`("[^"]+")|[\s]+`', $sChaine, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE));
		$this->evaluate();
	}
	
	private function evaluate() {
		while($this->oExpressionStack->valid()) {
			$sToken = $this->oExpressionStack->current();
			if(!class_exists($sToken)) {
				throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid expression '.$sToken);
			}
			$this->oExpressionStack->next();
			$mParam = $this->oExpressionStack->current();
			$interpreter = new ReflectionMethod($sToken, 'interpret');
			$interpreter->invoke(null, $this, $mParam);
			$this->oExpressionStack->next();
		}
	}
	
	public function getMove() {
		if(true === headers_sent()) {
			throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Unable to display image, headers already sent');
		}
		header('Content-type: image/png');
		imagepng($this->imh);
	}
	
	public function getSavedMove($sFile) {
		imagepng($this->imh, $sFile);
	}
	
	public function __get($sProp) {
		if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['gettable']) || false === $this->aCor[$sProp]['gettable']) {
			throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not gettable');
		}
		$sThisProp = $this->aCor[$sProp]['cor'];
		return $this->$sThisProp;
	}
	
	public function __set($sProp, $mVal) {
		if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['settable']) || false === $this->aCor[$sProp]['settable'] || !isset($this->aCor[$sProp]['type'])) {
			throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not settable');			
		}
		$sFunc = $this->aCor[$sProp]['type'];
		if(!$sFunc($mVal)) {
			throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Value '.$mVal.' is not a valid value for '.$sProp.'; waited : '.substr($sFunc, 3));	
		}
		if($sProp === 'COLOR') {
			color::interpret($this, $mVal);
			$this->sColor = $mVal;
		} elseif($sProp === 'PIXEL') {
			pixel::interpret($this, $mVal);
			$this->iThickNess = (int)$mVal;
		} elseif($sProp === 'FONTSIZE') {
			fontsize::interpret($this, $mVal);
			$this->iFontSize = (int)$mVal;
		} else {
			$sThisProp = $this->aCor[$sProp]['cor'];
			$this->$sThisProp = $mVal;
		}
	}
}
?>

Conclusion

Juste pour dire parce que c'est toujours agréable : ce code a terminé 6ème des Innovation Awards de novembre 2007 sur phpclasses.org :-)
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

07 octobre 2007 16:02:52 :
Ajout de 3 commandes : ellipse rectangle polygon
07 octobre 2007 16:03:30 :
oublié le code...
08 octobre 2007 22:46:11 :
Tite modif
08 octobre 2007 23:07:25 :
Compatibilité IE... (IE7 en tous cas).
01 novembre 2007 10:33:20 :
Rajout des modifications apportées par _KLESK : filledellipse et filledarc Rajout de 2 autres commandes : fontsize suivi d'un entier compris entre 1 et 5 fixe la taille de la police de caractère text suivi d'une chaîne délimitée par des guillemets (text "Hello World" par exemple) pour écrire ce texte
01 novembre 2007 10:33:43 :
Rajout des modifications apportées par _KLESK : filledellipse et filledarc Rajout de 2 autres commandes : fontsize suivi d'un entier compris entre 1 et 5 fixe la taille de la police de caractère text suivi d'une chaîne délimitée par des guillemets (text "Hello World" par exemple) pour écrire ce texte
01 novembre 2007 10:34:35 :
Oubli du code :-)
01 janvier 2008 10:16:34 :
RAS
  • signaler à un administrateur
    Commentaire de coucou747 le 08/10/2007 00:32:14

    Leider...

    faudrait vraiment que :
    tu uploades ton 3 eme tuto :) il m'interesse vraiment :)
    tu en rediges un sur ta facon de programmer en php (ou ce que tu consideres comme ideal), pourquoi ? parce-que t'es etonant a toujours mettre une ligne vide dans tes commentaires, et 4 lignes au lieu d'une seule :) au passage, sous doxygen :
    /**
      * chose
      */
    est equivalent a :
    //! chose

    en plus, tu ne documentes que tes classes, sans mettre de @brief, bref, je ne comprends pas du tout ta facon de commenter...

    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
    tu surcharges ton code alors que la pile d'appels te donne deja cette info...

    ton tas de classe aurait ete utile si il avait respecte la syntaxe exacte des path svg... la, c'est comme tu l'as dit, interessant, mais pas utile, c'est juste un cas concret d'un design... domage, t'aurais pu faire d'une pierre deux coup...
    cf : http://www.w3.org/TR/SVG/paths.html
    le travail d'un path est a peu pres identique a ceux de tes commandes, sauf qu'eux font du vectoriel...
    j'imagine bien un truc genre :

    un tas de classe de gestion xml <- svgChild <- path

    interface CommandeImage
    CommandeImage <- path
    CommandeImage <- malalam's_Class

    interface ImageHandler
    ImageHandler <- Gd
    ImageHandler <- ImageMagick

    avec la malalam's_Class qui aurait ete linkable vers un ImageHandler

  • signaler à un administrateur
    Commentaire de malalam le 08/10/2007 12:48:53 administrateur CS

    Hello,

    On verra ce soir si l'upload des tutos fonctionne :-)

    - Les commentaires : je commente généralement quand j'ai fini un code totalement. Là, j'ai continué à modifier des trucs, d'où le peu de commentaires. Ceux qui y sont ne sont que la copie du code très simplifié que j'ai fait pour le tuto. Ceci dit, je commente généralement ainsi (et c'est ainsi que je les mettrai) :
    méthode/classe/propriété
    @desc
    @var si propriété
    @param si méthode
    @return si méthode
    Ce sont les seuls tags que j'utilise généralement.
    Quant aux sauts de ligne : j'aime bien aérer mes codes en règle générale! ET pour le //, je ne trouve pas ça lisible. C'est vraiment simplement une préférence personnelle.

    - les exceptions : j'utilise tjrs la même base pour les exceptions : j'ai généralement une classe main ou generic qui envoie des mails/logge les exceptions avec une mise en page bien précise, d'où le passage en paramètre de __CLASS__ et de __METHOD__. Là j'ai conservé les mêmes appels mais j'ai supprimé la classe parente dont je n'avais pas besoin sur ce code. Eventuellement, je peux la rajouter pour conserver une cohérence. IL y a aussi que j'aime bien voir mes messages précédés de l'appel, en plus du backtrace.

    - je connais bien svg, mais ce n'était pas le but ici. J'ai voulu me caler sur GD uniquement. Ceci dit pourquoi pas imaginer différents moteurs graphiques possible en effet. On conserve l'interface, on crée des package de moteurs graphiques et un package général de classes abstraites mettant à jour les propriété, et une classe commande qui se charge du choix du moteur. Par exemple. Le "tas de classes" par contre est nécessaire dans tous les cas. Il permet d'ajouter facilement des fonctionnalités.

    Ceci dit, le but était effectivement simplement d'implémenter avec un exemple plus poussé, le design pattern interprète.

  • signaler à un administrateur
    Commentaire de coucou747 le 08/10/2007 19:18:29

    Ce que je voulais dire pour le svg, c'est que t'aurais pu parser un path ou autre pour afficher un path svg dans une image png...

  • signaler à un administrateur
    Commentaire de _klesk le 08/10/2007 22:03:40

    Bonsoir, je suis effectivement certain que ce code a une vertue certaine et je suis en ce moment a la recherche d'explication claire, précise et concies sur le comment du pourquoi des classes et la POO.

    Cependent je n'arrive pas a faire fonctionner ce code O_o.

    Cordialement.

  • signaler à un administrateur
    Commentaire de malalam le 08/10/2007 22:47:14 administrateur CS

    Que t'arrive-t-il avec au juste ? Pour rappel, je ne l'ai testé que sous Firefox (2), donc je ne sais pas ce qu'il en est sous IE, mais à mon avis...niet.

  • signaler à un administrateur
    Commentaire de malalam le 08/10/2007 22:47:48 administrateur CS

    Coucou => tu peux expliquer un peu plus précisément stp, je n'ai pas saisi de quoi tu parlais?

  • signaler à un administrateur
    Commentaire de coucou747 le 08/10/2007 23:03:14

    t'as fait ta propre syntaxe de commandes, utiliser celle du w3c aurait ete plus judicieux

  • signaler à un administrateur
    Commentaire de malalam le 08/10/2007 23:10:37 administrateur CS

    Bon ben voilà, c'est compatible IE, IE7 en tous cas.
    Coucou => le but était de faire un revival simplifié du LOGO. D'avoir un langage simple et compréhensible, simplement. Clairement, ce code n'a aucune autre utilité que d'être pédagogique et d'amuser 5mn. Je ne vais pas utiliser une syntaxe complexe pour ça.  right, yp, rectangle, color...ça a le mérite d'être compréhensible par tous. Un path svg...moins ;-)
    Si jamais je me lance dans un véritable éditeur graphique en php, par contre, pourquoi pas en effet! Parce que ça reste une très bonne idée. Mais pas sur ce code-ci.

  • signaler à un administrateur
    Commentaire de _klesk le 09/10/2007 19:35:48

    mon problème est simple :
    losque je prend les commandes qui sont proposer dans la doc (ex : right 40), il se passe rien, bien sur j'ai noter pour la compatibilitée FF.

    je n'est pas encore tester avec la MAJ.

  • signaler à un administrateur
    Commentaire de malalam le 09/10/2007 19:53:51 administrateur CS

    quelle est ta configuration ? Php et navigateur?

  • signaler à un administrateur
    Commentaire de _klesk le 09/10/2007 20:21:10

    ff 2.0.0.7 Ie 7 et php 5.2.1

  • signaler à un administrateur
    Commentaire de malalam le 09/10/2007 20:35:58 administrateur CS

    Ca c'est très bizarre parce que moi aussi...lol.
    mets toi en error_reporting(E_ALL) dans le script ajax (ajax/ajax.phpdraw.php). Il y a sûrement un message d'erreur. Ou alors, c'est le js mais Firefox devrait le dire.
    Difficile de debugger comme ça à distance. Dans le pire des cas, avec Firbug, tu devrais au moins voir  le message d'erreur arriver dans la requête POST d'Ajax (dans la console, en dépliant la requête, dans l'onglet réponse).

  • signaler à un administrateur
    Commentaire de _klesk le 09/10/2007 21:31:09

    je vient de regarder dans firebug et effectivement c'est bien au niveau de la requete POST, mais le gros probleme c'est le $_SERVER['document_root'], il semble poser probleme dans le require_once de inc/inc.main.php.

    En sachant que je suis dans un dossier du type www.lesite.com/~moi/phpdraw

    Je cherche encore si vous avez une idée je suis preneur :)

  • signaler à un administrateur
    Commentaire de _klesk le 09/10/2007 21:39:53

    A y est c'est bon.

    j'ai modifier inc.main.php a la ligne 4 en :define('PATH_CLASS', '../class/');
    tout simplement et la ca marche.

    j'ai du aussi bien sur chmoder tmpimg en 777 ;)

    Merci de votre aide.

  • signaler à un administrateur
    Commentaire de malalam le 09/10/2007 22:02:52 administrateur CS

    Ah ben oui le inc est paramétré pour mon chemin...:-) En effet, je n'y avais pas pensé.
    Ravi que ça fonctionne mieux :-)

  • signaler à un administrateur
    Commentaire de _klesk le 10/10/2007 00:14:14

    Du coup maintenant que ca marche j'ai etoffer le fichier class.interpreter.php de façon à avoir d'autre fonction, bien sur on peu en rajouter pas mal.

    <?php
    /**
    * Notre INTERFACE EXPRESSION
    *
    */
    interface expression {
    public static function interpret(interpreter $subject, $mParam);
    }

    /**
    * Une EXPRESSION CONCRETE pour les mouvements vers la droite
    *
    */
    class right implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
    }
    $mParam = (int)$mParam;
    if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X+$mParam, $subject->Y, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
    }
    $subject->X += $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour les mouvements vers la gauche
    *
    */
    class left implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
    }
    $mParam = (int)$mParam;
    if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X-$mParam, $subject->Y, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
    }
    $subject->X -= $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour les mouvements vers le haut
    *
    */
    class up implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
    }
    $mParam = (int)$mParam;
    if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y-$mParam, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
    }
    $subject->Y -= $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour les mouvements vers le bas
    *
    */
    class down implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid distance '.$mParam);
    }
    $mParam = (int)$mParam;
    if (false === imageline($subject->IMG, $subject->X, $subject->Y, $subject->X, $subject->Y+$mParam, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create line');
    }
    $subject->Y += $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la création d'une ellipse
    *
    */
    class ellipse implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(false === strpos($mParam, '-')) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
    }
    $aParam = explode('-', $mParam);
    $iWidth = (int)$aParam[0];
    $iHeight = (int)$aParam[1];
    if (false === imageellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create ellipse');
    }
    $subject->Y += $mParam;
    }
    }
    /**
    * Une EXPRESSION CONCRETE pour la création d'une ellipse remplie
    *
    */
    class filledellipse implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(false === strpos($mParam, '-')) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
    }
    $aParam = explode('-', $mParam);
    $iWidth = (int)$aParam[0];
    $iHeight = (int)$aParam[1];
    if (false === imagefilledellipse($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create ellipse');
    }
    $subject->Y += $mParam;
    }
    }
    /**
    * Une EXPRESSION CONCRETE pour la création d'un arc remplis
    *
    */
    class filledarc implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(false === strpos($mParam, '-')) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
    }
    $aParam = explode('-', $mParam);
    $iWidth = (int)$aParam[0];
    $iHeight = (int)$aParam[1];
    $iStart = (int)$aParam[2];
    $iEnd = (int)$aParam[3];
    if (false === imagefilledarc($subject->IMG, $subject->X, $subject->Y, $iWidth, $iHeight, $iStart, $iEnd, $subject->RCOLOR, IMG_ARC_PIE)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create ellipse');
    }
    $subject->Y += $mParam;
    }
    }


    /**
    * Une EXPRESSION CONCRETE pour la création d'un rectangle
    *
    */
    class rectangle implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(false === strpos($mParam, '-')) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
    }
    $aParam = explode('-', $mParam);
    $iX = (int)$aParam[0];
    $iY = (int)$aParam[1];
    if (false === imagerectangle($subject->IMG, $subject->X, $subject->Y, $iX, $iY, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create rectangle');
    }
    $subject->Y += $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la création d'un polygone
    *
    */
    class polygon implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(false === strpos($mParam, '-')) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid parameter '.$mParam);
    }
    $aParam = array_map ('intval', explode('-', $mParam));
    $iCount = count($aParam);
    if(0 !== $iCount%2) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : total points must be even : '.$iCount);
    }
    $iCount /= 2;
    if (false === imagepolygon($subject->IMG, $aParam, $iCount, $subject->RCOLOR)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to create polygon');
    }
    $subject->Y += $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la couleur du trait
    *
    */
    class color implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam) || 9 !== strlen($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid color '.$mParam);
    }
    $iRed = (int)substr($mParam, 0, 3);
    $iGreen = (int)substr($mParam, 3, 3);
    $iBlue = (int)substr($mParam, 6, 3);
    $subject->RCOLOR = imagecolorallocate($subject->IMG, $iRed, $iGreen, $iBlue);
    $subject->SCOLOR = $mParam;
    if(false === $subject->RCOLOR) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to allocate color '.$mParam);
    }
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la position X
    *
    */
    class x implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
    }
    $mParam = (int)$mParam;
    $subject->X = $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la position Y
    *
    */
    class y implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
    }
    $mParam = (int)$mParam;
    $subject->Y = $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour l'épaisseur du trait
    *
    */
    class pixel implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_numeric($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid position '.$mParam);
    }
    $mParam = (int)$mParam;
    if (false === imagesetthickness($subject->IMG, $mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to set thickness '.$mParam);
    }
    $subject->SPIXEL = $mParam;
    }
    }

    /**
    * Une EXPRESSION CONCRETE pour la sauvegarde de l'iamegs sous un nom particulier
    *
    */
    class file implements expression {
    public static function interpret(interpreter $subject, $mParam) {
    if(!is_string($mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid filename '.$mParam);
    }
    if (false === imagepng($subject->IMG, $mParam)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : Failed to ssave image to file '.$mParam);
    }
    }
    }

    /**
    * Notre INTERPRETER
    *
    */
    class interpreter {
    private $iX = 200;
    private $iY = 200;
    private $sColor;
    private $iWidth = 500;
    private $iHeight = 500;
    private $iThickNess = 1;
    private $aDefaultDim = array(500,500);
    private $oExpressionStack;
    private $imh;
    private $colorh;

    private $aCor = array(
    'X' => array('cor' => 'iX', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'Y' => array('cor' => 'iY', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'COLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
    'SCOLOR' => array('cor' => 'sColor', 'type' => 'is_string', 'gettable' => true, 'settable' => true),
    'RCOLOR' => array('cor' => 'colorh', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'WIDTH' => array('cor' => 'iWidth', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'HEIGHT' => array('cor' => 'iHeight', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'PIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'SPIXEL' => array('cor' => 'iThickNess', 'type' => 'is_int', 'gettable' => true, 'settable' => true),
    'IMG' => array('cor' => 'imh', 'type' => 'is_resource', 'gettable' => true, 'settable' => false)
    );

    public function __construct($sFile = null) {
    if(!is_null($sFile)) {
    $this->imh = @imagecreatefrompng($sFile);
    if(!$this->imh) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : '.$sFile.' has not been found');
    }
    } else {
    $this->imh = imagecreatetruecolor($this->iWidth, $this->iHeight);
    imagecolorallocate($this->imh, 0, 0, 0);
    }
    }

    public function interpret ($sChaine) {
    if(!is_string($sChaine)) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Parameter must be a string');
    }
    $this->oExpressionStack = new ArrayIterator(explode(' ', $sChaine));
    $this->evaluate();
    }

    private function evaluate() {
    while($this->oExpressionStack->valid()) {
    $sToken = $this->oExpressionStack->current();
    if(!class_exists($sToken)) {
    throw new languageException(__CLASS__.'::'.__FUNCTION__.'() : invalid expression '.$sToken);
    }
    $this->oExpressionStack->next();
    $mParam = $this->oExpressionStack->current();
    $interpreter = new ReflectionMethod($sToken, 'interpret');
    $interpreter->invoke(null, $this, $mParam);
    $this->oExpressionStack->next();
    }
    }

    public function getMove() {
    if(true === headers_sent()) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Unable to display image, headers already sent');
    }
    header('Content-type: image/png');
    imagepng($this->imh);
    }

    public function getSavedMove($sFile) {
    imagepng($this->imh, $sFile);
    }

    public function __get($sProp) {
    if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['gettable']) || false === $this->aCor[$sProp]['gettable']) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not gettable');
    }
    $sThisProp = $this->aCor[$sProp]['cor'];
    return $this->$sThisProp;
    }

    public function __set($sProp, $mVal) {
    if(!array_key_exists($sProp, $this->aCor) || !isset($this->aCor[$sProp]['settable']) || false === $this->aCor[$sProp]['settable'] || !isset($this->aCor[$sProp]['type'])) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Property '.$sProp.' is not settable');
    }
    $sFunc = $this->aCor[$sProp]['type'];
    if(!$sFunc($mVal)) {
    throw new functionnalException(__CLASS__.'::'.__FUNCTION__.'() : Value '.$mVal.' is not a valid value for '.$sProp.'; waited : '.substr($sFunc, 3));
    }
    if($sProp === 'COLOR') {
    color::interpret($this, $mVal);
    $this->sColor = $mVal;
    } elseif($sProp === 'PIXEL') {
    pixel::interpret($this, $mVal);
    $this->iThickNess = (int)$mVal;
    } else {
    $sThisProp = $this->aCor[$sProp]['cor'];
    $this->$sThisProp = $mVal;
    }
    }
    }
    ?>

    et avec ces rajout et ce code on peut obtenir des truc sympa

    le bien / le mal :

    x 250 y 250 filledarc 500-500-90-270 x 250 y 250 filledarc 500-500-270-180 x 250 y 250 ellipse 500-500 x 250 y 125 ellipse 250-250 x 250 y 375 color 255255255 filledellipse 250-250 color 000000000 x 253 y 125 filledellipse 247-250 color 255255255 x 250 y 125 filledellipse 110-110 color 000000000 x 250 y 375 filledellipse 110-110