File "filtres_images.php"

Full path: /home/meharicl/www/ecrire/inc/filtres_images.php
File size: 75.62 B
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php
/***************************************************************************\
 *  SPIP, Systeme de publication pour l'internet                           *
 *                                                                         *
 *  Copyright (c) 2001-2009                                                *
 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
 *                                                                         *
 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
\***************************************************************************/

include_spip('inc/filtres_images_mini');

// Transforme l'image en PNG transparent
// alpha = 0: aucune transparence
// alpha = 127: completement transparent
// http://doc.spip.org/@image_alpha
function image_alpha($im, $alpha = 63)
{
	$fonction = array('image_alpha', func_get_args());
	$image = image_valeurs_trans($im, "alpha-$alpha", "png",$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		// Creation de l'image en deux temps
		// de facon a conserver les GIF transparents
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im2 = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im2, false);
		@imagesavealpha($im2,true);
		$color_t = ImageColorAllocateAlpha( $im2, 255, 255, 255 , 127 );
		imagefill ($im2, 0, 0, $color_t);
		imagecopy($im2, $im, 0, 0, 0, 0, $x_i, $y_i);

		$im_ = imagecreatetruecolor($x_i, $y_i);
		imagealphablending ($im_, FALSE );
		imagesavealpha ( $im_, TRUE );



		for ($x = 0; $x < $x_i; $x++) {
			for ($y = 0; $y < $y_i; $y++) {
				$rgb = ImageColorAt($im2, $x, $y);
				
				if (function_exists('imagecolorallocatealpha')) {
					$a = ($rgb >> 24) & 0xFF;
					$r = ($rgb >> 16) & 0xFF;
					$g = ($rgb >> 8) & 0xFF;
					$b = $rgb & 0xFF;
					
					
					$a_ = $alpha + $a - round($a*$alpha/127);
					$rgb = imagecolorallocatealpha($im_, $r, $g, $b, $a_);
				}
				imagesetpixel ( $im_, $x, $y, $rgb );
			}
		}
		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
		imagedestroy($im2);
	}
	

	return image_ecrire_tag($image,array('src'=>$dest));
	
}

// http://doc.spip.org/@image_recadre
function image_recadre($im,$width,$height,$position='center', $background_color='white')
{
	$fonction = array('image_recadre', func_get_args());
	$image = image_valeurs_trans($im, "recadre-$width-$height-$position-$background_color",false,$fonction);
	
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	if ($width==0) $width=$x_i;
	if ($height==0) $height=$y_i;
	
	$offset_width = $x_i-$width;
	$offset_height = $y_i-$height;
	$position=strtolower($position);
	if (strpos($position,'left')!==FALSE){
		if (preg_match(';left=(\d{1}\d+);', $position, $left)){
			$offset_width=$left[1];	
		}
		else{
			$offset_width=0;
		}
	}
	elseif (strpos($position,'right')!==FALSE)
		$offset_width=$offset_width;
	else
		$offset_width=intval(ceil($offset_width/2));

	if (strpos($position,'top')!==FALSE){
		if (preg_match(';top=(\d{1}\d+);', $position, $top)){
			$offset_height=$top[1];
		}
		else{
			$offset_height=0;
		}
	}
	elseif (strpos($position,'bottom')!==FALSE)
		$offset_height=$offset_height;
	else
		$offset_height=intval(ceil($offset_height/2));
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($width, $height);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);

		if ($background_color=='transparent')
			$color_t = imagecolorallocatealpha( $im_, 255, 255, 255 , 127 );
		else {
			$bg = couleur_hex_to_dec($background_color);
			$color_t = imagecolorallocate( $im_, $bg['red'], $bg['green'], $bg['blue']);
		}
		imagefill ($im_, 0, 0, $color_t);
		imagecopy($im_, $im, max(0,-$offset_width), max(0,-$offset_height), max(0,$offset_width), max(0,$offset_height), min($width,$x_i), min($height,$y_i));

		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
	}
	
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>$width,'height'=>$height));
}

// http://doc.spip.org/@image_flip_vertical
function image_flip_vertical($im)
{
	$fonction = array('image_flip_vertical', func_get_args());
	$image = image_valeurs_trans($im, "flip_v", false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
	
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);

		for ($x = 0; $x < $x_i; $x++) {
			for ($y = 0; $y < $y_i; $y++) {
				imagecopy($im_, $im, $x_i - $x - 1, $y, $x, $y, 1, 1);
			}
		}

		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
	}
	
	return image_ecrire_tag($image,array('src'=>$dest));
}

// http://doc.spip.org/@image_flip_horizontal
function image_flip_horizontal($im)
{
	$fonction = array('image_flip_horizontal', func_get_args());
	$image = image_valeurs_trans($im, "flip_h",false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
	
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);

		for ($x = 0; $x < $x_i; $x++) {
			for ($y = 0; $y < $y_i; $y++) {
   				imagecopy($im_, $im, $x, $y_i - $y - 1, $x, $y, 1, 1);
			}
		}
		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
	}
	
	return image_ecrire_tag($image,array('src'=>$dest));
}

// http://doc.spip.org/@image_masque
function image_masque($im, $masque, $pos="") {
	// Passer, en plus de l'image d'origine,
	// une image de "masque": un fichier PNG24 transparent.
	// Le decoupage se fera selon la transparence du "masque",
	// et les couleurs seront eclaircies/foncees selon de couleur du masque.
	// Pour ne pas modifier la couleur, le masque doit etre en gris 50%.
	//
	// Si l'image source est plus grande que le masque, alors cette image est reduite a la taille du masque.
	// Sinon, c'est la taille de l'image source qui est utilisee.
	//
	// $pos est une variable libre, qui permet de passer left=..., right=..., bottom=..., top=...
	// dans ce cas, le pasque est place a ces positions sur l'image d'origine,
	// et evidemment cette image d'origine n'est pas redimensionnee
	// 
	// Positionnement horizontal: text-align=left, right, center
	// Positionnement vertical : vertical-align: top, bottom, middle
	// (les positionnements left, right, top, left sont relativement inutiles, mais coherence avec CSS)
	//
	// Choix du mode de fusion: mode=masque, normal, eclaircir, obscurcir, produit, difference
	// masque: mode par defaut
	// normal: place la nouvelle image par dessus l'ancienne
	// eclaircir: place uniquement les points plus clairs
	// obscurcir: place uniquement les points plus fonc'es
	// produit: multiplie par le masque (points noirs rendent l'image noire, points blancs ne changent rien)
	// difference: remplit avec l'ecart entre les couleurs d'origine et du masque

	$mode = "masque";


	$numargs = func_num_args();
	$arg_list = func_get_args();
	$texte = $arg_list[0];
	for ($i = 1; $i < $numargs; $i++) {
		if ( ($p = strpos($arg_list[$i],"=")) !==false) {
			$nom_variable = substr($arg_list[$i], 0, $p);
			$val_variable = substr($arg_list[$i], $p+1);
			$variable["$nom_variable"] = $val_variable;
			$defini["$nom_variable"] = 1;
		}
	}
	if ($defini["mode"]) $mode = $variable["mode"];

	$masque = find_in_path($masque);
	$pos = md5(serialize($variable).@filemtime($masque));

	$fonction = array('image_masque', func_get_args());
	$image = image_valeurs_trans($im, "masque-$masque-$pos", "png",$fonction);
	if (!$image) return("");

	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];


	if ($defini["right"] OR $defini["left"] OR $defini["bottom"] OR $defini["top"] OR $defini["text-align"] OR $defini["vertical-align"]) {
		$placer = true;
	}
	else $placer = false;

	if ($creer) {
		
		$mask = image_valeurs_trans($masque,"");
		if (!is_array($mask)) return("");
		$im_m = $mask["fichier"];
		$x_m = $mask["largeur"];
		$y_m = $mask["hauteur"];
	
		$im2 = $mask["fonction_imagecreatefrom"]($masque);
		if ($mask["format_source"] == "gif" AND function_exists('ImageCopyResampled')) { 
			$im2_ = imagecreatetruecolor($x_m, $y_m);
			// Si un GIF est transparent, 
			// fabriquer un PNG transparent  
			// Conserver la transparence 
			if (function_exists("imageAntiAlias")) imageAntiAlias($im2_,true); 
			@imagealphablending($im2_, false); 
			@imagesavealpha($im2_,true); 
			@ImageCopyResampled($im2_, $im2, 0, 0, 0, 0, $x_m, $y_m, $x_m, $y_m);
			imagedestroy($im2);
			$im2 = $im2_;
		}
		
		if ($placer) {
			// On fabriquer une version "agrandie" du masque,
			// aux dimensions de l'image source
			// et on "installe" le masque dans cette image
			// ainsi: aucun redimensionnement
			
			$dx = 0;
			$dy = 0;
			
			if ($defini["right"]) {
				$right = $variable["right"];
				$dx = ($x_i - $x_m) - $right;
			}
			if ($defini["bottom"]) {
				$bottom = $variable["bottom"];
				$dy = ($y_i - $y_m) - $bottom;
				}
			if ($defini["top"]) {
				$top = $variable["top"];
				$dy = $top;
			}
			if ($defini["left"]) {
				$left = $variable["left"];
				$dx = $left;
			}
			if ($defini["text-align"]) {
				$align = $variable["text-align"];
				if ($align == "right") {
					$right = 0;
					$dx = ($x_i - $x_m);
				} else if ($align == "left") {
					$left = 0;
					$dx = 0;
				} else if ($align = "center") {
					$dx = round( ($x_i - $x_m) / 2 ) ;
				}
			}
			if ($defini["vertical-align"]) {
				$valign = $variable["vertical-align"];
				if ($valign == "bottom") {
					$bottom = 0;
					$dy = ($y_i - $y_m);
				} else if ($valign == "top") {
					$top = 0;
					$dy = 0;
				} else if ($valign = "middle") {
					$dy = round( ($y_i - $y_m) / 2 ) ;
				}
			}
			
			
			$im3 = imagecreatetruecolor($x_i, $y_i);
			@imagealphablending($im3, false);
			@imagesavealpha($im3,true);
			if ($mode == "masque") $color_t = ImageColorAllocateAlpha( $im3, 128, 128, 128 , 0 );
			else $color_t = ImageColorAllocateAlpha( $im3, 128, 128, 128 , 127 );
			imagefill ($im3, 0, 0, $color_t);

			

			imagecopy ( $im3, $im2, $dx, $dy, 0, 0, $x_m, $y_m);	

			imagedestroy($im2);
			$im2 = imagecreatetruecolor($x_i, $y_i);
			@imagealphablending($im2, false);
			@imagesavealpha($im2,true);
			
			
			
			imagecopy ( $im2, $im3, 0, 0, 0, 0, $x_i, $y_i);			
			imagedestroy($im3);
			$x_m = $x_i;
			$y_m = $y_i;
		}
		
	
		$rapport = $x_i / $x_m;
		if (($y_i / $y_m) < $rapport ) {
			$rapport = $y_i / $y_m;
		}
			
		$x_d = ceil($x_i / $rapport);
		$y_d = ceil($y_i / $rapport);
		

		if ($x_i < $x_m OR $y_i < $y_m) {
			$x_dest = $x_i;
			$y_dest = $y_i;
			$x_dec = 0;
			$y_dec = 0;
		} else {
			$x_dest = $x_m;
			$y_dest = $y_m;
			$x_dec = round(($x_d - $x_m) /2);
			$y_dec = round(($y_d - $y_m) /2);
		}


		$nouveau = image_valeurs_trans(image_reduire($im, $x_d, $y_d),"");
		if (!is_array($nouveau)) return("");
		$im_n = $nouveau["fichier"];
		
	
		$im = $nouveau["fonction_imagecreatefrom"]($im_n);
		imagepalettetotruecolor($im);
		if ($nouveau["format_source"] == "gif" AND function_exists('ImageCopyResampled')) { 
			$im_ = imagecreatetruecolor($x_dest, $y_dest);
			// Si un GIF est transparent, 
			// fabriquer un PNG transparent  
			// Conserver la transparence 
			if (function_exists("imageAntiAlias")) imageAntiAlias($im_,true); 
			@imagealphablending($im_, false); 
			@imagesavealpha($im_,true); 
			@ImageCopyResampled($im_, $im, 0, 0, 0, 0, $x_dest, $y_dest, $x_dest, $y_dest);
			imagedestroy($im);
			$im = $im_;
		}
		$im_ = imagecreatetruecolor($x_dest, $y_dest);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);


		for ($x = 0; $x < $x_dest; $x++) {
			for ($y=0; $y < $y_dest; $y++) {
				$rgb = ImageColorAt($im2, $x, $y);
				$a = ($rgb >> 24) & 0xFF;
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;
				

				$rgb2 = ImageColorAt($im, $x+$x_dec, $y+$y_dec);
				$a2 = ($rgb2 >> 24) & 0xFF;
				$r2 = ($rgb2 >> 16) & 0xFF;
				$g2 = ($rgb2 >> 8) & 0xFF;
				$b2 = $rgb2 & 0xFF;
				
				
				
				if ($mode == "normal") {
					$v = (127 - $a) / 127;
					if ($v == 1) {
						$r_ = $r;
						$g_ = $g;
						$b_ = $b;
					} else {
						$v2 = (127 - $a2) / 127;
						if ($v+$v2 == 0) {
							$r_ = $r2;
							$g_ = $g2;
							$b_ = $b2;
						} else if ($v2 ==0) {
							$r_ = $r;
							$g_ = $g;
							$b_ = $b;
						} else if ($v == 0) {
							$r_ = $r2;
							$g_ = $g2;
							$b_ = $b2;
						}else {
							$r_ = $r + (($r2 - $r) * $v2 * (1 - $v));
							$g_ = $g + (($g2 - $g) * $v2 * (1 - $v));
							$b_ = $b + (($b2 - $b) * $v2 * (1 - $v));
						}
					}
					$a_ = min($a,$a2);
				} elseif ($mode == "produit" OR $mode == "difference") {					

					if ($mode == "produit") {
						$r = ($r/255) * $r2;
						$g = ($g/255) * $g2;
						$b = ($b/255) * $b2;
					} else if ($mode == "difference") {
						$r = abs($r-$r2);
						$g = abs($g-$g2);
						$b = abs($b-$b2);				
					}

					$r = max(0, min($r, 255));
					$g = max(0, min($g, 255));
					$b = max(0, min($b, 255));

					$v = (127 - $a) / 127;
					if ($v == 1) {
						$r_ = $r;
						$g_ = $g;
						$b_ = $b;
					} else {
						$v2 = (127 - $a2) / 127;
						if ($v+$v2 == 0) {
							$r_ = $r2;
							$g_ = $g2;
							$b_ = $b2;
						} else {
							$r_ = $r + (($r2 - $r) * $v2 * (1 - $v));
							$g_ = $g + (($g2 - $g) * $v2 * (1 - $v));
							$b_ = $b + (($b2 - $b) * $v2 * (1 - $v));
						}
					}


					$a_ = $a2;
				} elseif ($mode == "eclaircir" OR $mode == "obscurcir") {
					$v = (127 - $a) / 127;
					if ($v == 1) {
						$r_ = $r;
						$g_ = $g;
						$b_ = $b;
					} else {
						$v2 = (127 - $a2) / 127;
						if ($v+$v2 == 0) {
							$r_ = $r2;
							$g_ = $g2;
							$b_ = $b2;
						} else {
							$r_ = $r + (($r2 - $r) * $v2 * (1 - $v));
							$g_ = $g + (($g2 - $g) * $v2 * (1 - $v));
							$b_ = $b + (($b2 - $b) * $v2 * (1 - $v));
						}
					}
					if ($mode == "eclaircir") {
						$r_ = max ($r_, $r2);
						$g_ = max ($g_, $g2);
						$b_ = max ($b_, $b2);
					} else {
						$r_ = min ($r_, $r2);
						$g_ = min ($g_, $g2);
						$b_ = min ($b_, $b2);					
					}
					
					$a_ = min($a,$a2);
				} else {
					$r_ = $r2 + 1 * ($r - 127);
					$r_ = max(0, min($r_, 255));
					$g_ = $g2 + 1 * ($g - 127);
					$g_ = max(0, min($g_, 255));
					$b_ = $b2 + 1 * ($b - 127);
					$b_ = max(0, min($b_, 255));
					
					$a_ = $a + $a2 - round($a*$a2/127);
				}

				$color = ImageColorAllocateAlpha( $im_, $r_, $g_, $b_ , $a_ );
				imagesetpixel ($im_, $x, $y, $color);			
			}
		}

		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
		imagedestroy($im2);

	}
	$x_dest = largeur($dest);
	$y_dest = hauteur($dest);
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>$x_dest,'height'=>$y_dest));
}

// Passage de l'image en noir et blanc
// un noir & blanc "photo" n'est pas "neutre": les composantes de couleur sont
// ponderees pour obtenir le niveau de gris;
// on peut ici regler cette ponderation en "pour mille"
// http://doc.spip.org/@image_nb
function image_nb($im, $val_r = 299, $val_g = 587, $val_b = 114)
{
	$fonction = array('image_nb', func_get_args());
	$image = image_valeurs_trans($im, "nb-$val_r-$val_g-$val_b",false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	// Methode precise
	// resultat plus beau, mais tres lourd
	// Et: indispensable pour preserver transparence!

	if ($creer) {
		// Creation de l'image en deux temps
		// de facon a conserver les GIF transparents
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);
		imagecopy($im_, $im, 0, 0, 0, 0, $x_i, $y_i);
		
		for ($x = 0; $x < $x_i; $x++) {
			for ($y=0; $y < $y_i; $y++) {
				$rgb = ImageColorAt($im_, $x, $y);
				$a = ($rgb >> 24) & 0xFF;
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;

				$c = round(($val_r * $r / 1000) + ($val_g * $g / 1000) + ($val_b * $b / 1000));
				if ($c < 0) $c = 0;
				if ($c > 254) $c = 254;
				
				
				$color = ImageColorAllocateAlpha( $im_, $c, $c, $c , $a );
				imagesetpixel ($im_, $x, $y, $color);			
			}
		}
		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
	}

	return image_ecrire_tag($image,array('src'=>$dest));
}

// http://doc.spip.org/@image_flou
function image_flou($im,$niveau=3)
{
	// Il s'agit d'une modification du script blur qu'on trouve un peu partout:
	// + la transparence est geree correctement
	// + les dimensions de l'image sont augmentees pour flouter les bords
	$coeffs = array (
				array ( 1),
				array ( 1, 1), 
				array ( 1, 2, 1),
				array ( 1, 3, 3, 1),
				array ( 1, 4, 6, 4, 1),
				array ( 1, 5, 10, 10, 5, 1),
				array ( 1, 6, 15, 20, 15, 6, 1),
				array ( 1, 7, 21, 35, 35, 21, 7, 1),
				array ( 1, 8, 28, 56, 70, 56, 28, 8, 1),
				array ( 1, 9, 36, 84, 126, 126, 84, 36, 9, 1),
				array ( 1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1),
				array ( 1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1)
				);
	
	$fonction = array('image_flou', func_get_args());
	$image = image_valeurs_trans($im, "flou-$niveau", false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	$sum = pow (2, $niveau);

	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	// Methode precise
	// resultat plus beau, mais tres lourd
	// Et: indispensable pour preserver transparence!

	if ($creer) {
		// Creation de l'image en deux temps
		// de facon a conserver les GIF transparents
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$temp1 = imagecreatetruecolor($x_i+$niveau, $y_i);
		$temp2 = imagecreatetruecolor($x_i+$niveau, $y_i+$niveau);
		
		@imagealphablending($temp1, false);
		@imagesavealpha($temp1,true);
		@imagealphablending($temp2, false);
		@imagesavealpha($temp2,true);

		
		for ($i = 0; $i < $x_i+$niveau; $i++) {
			for ($j=0; $j < $y_i; $j++) {
				$suma=0;
				$sumr=0;
				$sumg=0;
				$sumb=0;
				$sum = 0;
				$sum_ = 0;
				for ( $k=0 ; $k <= $niveau ; ++$k ) {
					$color = imagecolorat($im, $i_ = ($i-$niveau)+$k , $j);

					$a = ($color >> 24) & 0xFF;
					$r = ($color >> 16) & 0xFF;
					$g = ($color >> 8) & 0xFF;
					$b = ($color) & 0xFF;
					
					if ($i_ < 0 OR $i_ >= $x_i) $a = 127;
					
					$coef = $coeffs[$niveau][$k];
					$suma += $a*$coef;
					$ac = ((127-$a) / 127);
					
					$ac = $ac*$ac;
					
					$sumr += $r * $coef * $ac;
					$sumg += $g * $coef * $ac;
					$sumb += $b * $coef * $ac;
					$sum += $coef * $ac;
					$sum_ += $coef;
				}
				if ($sum > 0) $color = ImageColorAllocateAlpha ($temp1, $sumr/$sum, $sumg/$sum, $sumb/$sum, $suma/$sum_);
				else $color = ImageColorAllocateAlpha ($temp1, 255, 255, 255, 127);
				imagesetpixel($temp1,$i,$j,$color);
			}
		}
		imagedestroy($im);
		for ($i = 0; $i < $x_i+$niveau; $i++) {
			for ($j=0; $j < $y_i+$niveau; $j++) {
				$suma=0;
				$sumr=0;
				$sumg=0;
				$sumb=0;
				$sum = 0;
				$sum_ = 0;
				for ( $k=0 ; $k <= $niveau ; ++$k ) {
					$color = imagecolorat($temp1, $i, $j_ = $j-$niveau+$k);
					$a = ($color >> 24) & 0xFF;
					$r = ($color >> 16) & 0xFF;
					$g = ($color >> 8) & 0xFF;
					$b = ($color) & 0xFF;
					if ($j_ < 0 OR $j_ >= $y_i) $a = 127;
					
					$suma += $a*$coeffs[$niveau][$k];
					$ac = ((127-$a) / 127);
										
					$sumr += $r * $coeffs[$niveau][$k] * $ac;
					$sumg += $g * $coeffs[$niveau][$k] * $ac;
					$sumb += $b * $coeffs[$niveau][$k] * $ac;
					$sum += $coeffs[$niveau][$k] * $ac;
					$sum_ += $coeffs[$niveau][$k];
					
				}
				if ($sum > 0) $color = ImageColorAllocateAlpha ($temp2, $sumr/$sum, $sumg/$sum, $sumb/$sum, $suma/$sum_);
				else $color = ImageColorAllocateAlpha ($temp2, 255, 255, 255, 127);
				imagesetpixel($temp2,$i,$j,$color);
			}
		}
	
		image_gd_output($temp2,$image);
		imagedestroy($temp1);	
		imagedestroy($temp2);	
	}
	
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>($x_i+$niveau),'height'=>($y_i+$niveau)));
}

// http://doc.spip.org/@image_RotateBicubic
function image_RotateBicubic($src_img, $angle, $bicubic=0) {
   
   if (round($angle/90)*90 == $angle) {
		$droit = true;
   		if (round($angle/180)*180 == $angle) $rot = 180;
   		else $rot = 90;
   }
   else $droit = false;
   
  // convert degrees to radians
   $angle = $angle + 180;
   $angle = deg2rad($angle);
  


   $src_x = imagesx($src_img);
   $src_y = imagesy($src_img);
   
  
   $center_x = floor(($src_x-1)/2);
   $center_y = floor(($src_y-1)/2);

   $cosangle = cos($angle);
   $sinangle = sin($angle);

	// calculer dimensions en simplifiant angles droits, ce qui evite "floutage"
	// des rotations a angle droit
	if (!$droit) {
	   $corners=array(array(0,0), array($src_x,0), array($src_x,$src_y), array(0,$src_y));
	
	   foreach($corners as $key=>$value) {
		 $value[0]-=$center_x;        //Translate coords to center for rotation
		 $value[1]-=$center_y;
		 $temp=array();
		 $temp[0]=$value[0]*$cosangle+$value[1]*$sinangle;
		 $temp[1]=$value[1]*$cosangle-$value[0]*$sinangle;
		 $corners[$key]=$temp;    
	   }
	   
	   $min_x=1000000000000000;
	   $max_x=-1000000000000000;
	   $min_y=1000000000000000;
	   $max_y=-1000000000000000;
	   
	   foreach($corners as $key => $value) {
		 if($value[0]<$min_x)
		   $min_x=$value[0];
		 if($value[0]>$max_x)
		   $max_x=$value[0];
	   
		 if($value[1]<$min_y)
		   $min_y=$value[1];
		 if($value[1]>$max_y)
		   $max_y=$value[1];
	   }
	
	   $rotate_width=ceil($max_x-$min_x);
	   $rotate_height=ceil($max_y-$min_y);
   }
   else {
   	if ($rot == 180) {
   		$rotate_height = $src_y;
   		$rotate_width = $src_x;
   	} else {
   		$rotate_height = $src_x;
   		$rotate_width = $src_y;
   	}
   	$bicubic = false;
   }
   
   
   $rotate=imagecreatetruecolor($rotate_width,$rotate_height);
   imagealphablending($rotate, false);
   imagesavealpha($rotate, true);

   $cosangle = cos($angle);
   $sinangle = sin($angle);
   
	// arrondir pour rotations angle droit (car cos et sin dans {-1,0,1})
	if ($droit) {
		$cosangle = round($cosangle);
		$sinangle = round($sinangle);
	}

   $newcenter_x = ($rotate_width-1)/2;
   $newcenter_y = ($rotate_height-1)/2;

   
   for ($y = 0; $y < $rotate_height; $y++) {
     for ($x = 0; $x < $rotate_width; $x++) {
   // rotate...
       $old_x = ((($newcenter_x-$x) * $cosangle + ($newcenter_y-$y) * $sinangle))
         + $center_x;
       $old_y = ((($newcenter_y-$y) * $cosangle - ($newcenter_x-$x) * $sinangle))
         + $center_y;  
         
         $old_x = ceil($old_x);
         $old_y = ceil($old_y);
         
   if ( $old_x >= 0 && $old_x < $src_x
         && $old_y >= 0 && $old_y < $src_y ) {
     if ($bicubic == true) {
       $xo = $old_x;
       $x0 = floor($xo);
       $x1 = ceil($xo);
       $yo = $old_y;
       $y0 = floor($yo);
       $y1 = ceil($yo);
       
		// on prend chaque point, mais on pondere en fonction de la distance
		$rgb = ImageColorAt($src_img, $x0, $y0); 
		$a1 = ($rgb >> 24) & 0xFF;
		$r1 = ($rgb >> 16) & 0xFF;
		$g1 = ($rgb >> 8) & 0xFF;
		$b1 = $rgb & 0xFF;
		$d1 = image_distance_pixel($xo, $yo, $x0, $y0);

		$rgb = ImageColorAt($src_img, $x1, $y0); 
		$a2 = ($rgb >> 24) & 0xFF;
		$r2 = ($rgb >> 16) & 0xFF;
		$g2 = ($rgb >> 8) & 0xFF;
		$b2 = $rgb & 0xFF;
		$d2 = image_distance_pixel($xo, $yo, $x1, $y0);

		$rgb = ImageColorAt($src_img,$x0, $y1); 
		$a3 = ($rgb >> 24) & 0xFF;
		$r3 = ($rgb >> 16) & 0xFF;
		$g3 = ($rgb >> 8) & 0xFF;
		$b3 = $rgb & 0xFF;
		$d3 = image_distance_pixel($xo, $yo, $x0, $y1);

		$rgb = ImageColorAt($src_img,$x1, $y1);
		$a4 = ($rgb >> 24) & 0xFF;
		$r4 = ($rgb >> 16) & 0xFF;
		$g4 = ($rgb >> 8) & 0xFF;
		$b4 = $rgb & 0xFF;
		$d4 = image_distance_pixel($xo, $yo, $x1, $y1);

		$ac1 = ((127-$a1) / 127);
		$ac2 = ((127-$a2) / 127);
		$ac3 = ((127-$a3) / 127);
		$ac4 = ((127-$a4) / 127);
		
		// limiter impact des couleurs transparentes, 
		// mais attention tout transp: division par 0
		if ($ac1*$d1 + $ac2*$d2 + $ac3+$d3 + $ac4+$d4 > 0) {
			if ($ac1 > 0) $d1 = $d1 * $ac1;
			if ($ac2 > 0) $d2 = $d2 * $ac2;
			if ($ac3 > 0) $d3 = $d3 * $ac3;
			if ($ac4 > 0) $d4 = $d4 * $ac4;
		}
		
		$tot  = $d1 + $d2 + $d3 + $d4;

       $r = round((($d1*$r1)+($d2*$r2)+($d3*$r3)+($d4*$r4))/$tot);
       $g = round((($d1*$g1+($d2*$g2)+$d3*$g3+$d4*$g4))/$tot);
       $b = round((($d1*$b1+($d2*$b2)+$d3*$b3+$d4*$b4))/$tot);
       $a = round((($d1*$a1+($d2*$a2)+$d3*$a3+$d4*$a4))/$tot);
        $color = imagecolorallocatealpha($src_img, $r,$g,$b,$a);
     } else {
       $color = imagecolorat($src_img, round($old_x), round($old_y));
     }
   } else {
         // this line sets the background colour
     $color = imagecolorallocatealpha($src_img, 255, 255, 255, 127);
   }
   @imagesetpixel($rotate, $x, $y, $color);
     }
   }
   return $rotate;
}

// permet de faire tourner une image d'un angle quelconque
// la fonction "crop" n'est pas implementee...
// http://doc.spip.org/@image_rotation
function image_rotation($im, $angle, $crop=false)
{
	$fonction = array('image_rotation', func_get_args());
	$image = image_valeurs_trans($im, "rot-$angle-$crop", "png", $fonction);
	if (!$image) return("");
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		$effectuer_gd = true;

		if (function_exists('imagick_rotate')) {
			$mask = imagick_getcanvas( "#ff0000", $x, $y );
			$handle = imagick_readimage ($im);
			if ($handle && imagick_isopaqueimage( $handle )) {
				imagick_rotate( $handle, $angle);
				imagick_writeimage( $handle, $dest);
				$effectuer_gd = false;
			}
		}
		elseif(is_callable(array('Imagick','rotateImage'))){
			$imagick = new Imagick();
			$imagick->readImage($im);
			$imagick->rotateImage(new ImagickPixel('#ffffff'), $angle);
			$imagick->writeImage($dest);
			$effectuer_gd = false;
		}
		if ($effectuer_gd) {
			// Creation de l'image en deux temps
			// de facon a conserver les GIF transparents
			$im = $image["fonction_imagecreatefrom"]($im);
			imagepalettetotruecolor($im);
			$im = image_RotateBicubic($im, $angle, true);
			image_gd_output($im,$image);
			imagedestroy($im);
		}
	}
	list ($src_y,$src_x) = taille_image($dest);
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>$src_x,'height'=>$src_y));
}

// Permet d'appliquer un filtre php_imagick a une image
// par exemple: [(#LOGO_ARTICLE||image_imagick{imagick_wave,20,60})]
// liste des fonctions: http://www.linux-nantes.org/~fmonnier/doc/imagick/
// http://doc.spip.org/@image_imagick
function image_imagick () {
	$tous = func_get_args();
	$img = $tous[0];
	$fonc = $tous[1];
	$tous[0]="";
	$tous_var = join($tous, "-");

	$fonction = array('image_imagick', func_get_args());
	$image = image_valeurs_trans($img, "$tous_var", "png",$fonction);
	if (!$image) return("");
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		if (function_exists($fonc)) {

			$handle = imagick_readimage ($im);
			$arr[0] = $handle;
			for ($i=2; $i < count($tous); $i++) $arr[] = $tous[$i];
			call_user_func_array($fonc, $arr);
			// Creer image dans fichier temporaire, puis renommer vers "bon" fichier
			// de facon a eviter time_out pendant creation de l'image definitive
			$tmp = preg_replace(",[.]png$,i", "-tmp.png", $dest);
			imagick_writeimage( $handle, $tmp);
			rename($tmp, $dest);
			ecrire_fichier($dest.".src",serialize($image));
		} 
	}
	list ($src_y,$src_x) = taille_image($dest);
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>$src_x,'height'=>$src_y));

}


// $src_img - a GD image resource
// $angle - degrees to rotate clockwise, in degrees
// returns a GD image resource
// script de php.net lourdement corrig'e
// (le bicubic deconnait completement,
// et j'ai ajoute la ponderation par la distance au pixel)

// http://doc.spip.org/@image_distance_pixel
function image_distance_pixel($xo, $yo, $x0, $y0) {
	$vx = $xo - $x0;
	$vy = $yo - $y0;
	$d = 1 - (sqrt(($vx)*($vx) + ($vy)*($vy)) / sqrt(2));
	return $d;
}

// http://doc.spip.org/@image_decal_couleur
function image_decal_couleur($coul, $gamma) {
	$coul = $coul + $gamma;
	
	if ($coul > 255) $coul = 255;
	if ($coul < 0) $coul = 0;
	return $coul;
}
// Permet de rendre une image
// plus claire (gamma > 0)
// ou plus foncee (gamma < 0)
// http://doc.spip.org/@image_gamma
function image_gamma($im, $gamma = 0)
{
	$fonction = array('image_gamma', func_get_args());
	$image = image_valeurs_trans($im, "gamma-$gamma",false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		// Creation de l'image en deux temps
		// de facon a conserver les GIF transparents
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);
		imagecopy($im_, $im, 0, 0, 0, 0, $x_i, $y_i);
	
		for ($x = 0; $x < $x_i; $x++) {
			for ($y=0; $y < $y_i; $y++) {
				$rgb = ImageColorAt($im_, $x, $y);
				$a = ($rgb >> 24) & 0xFF;
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;

				$r = image_decal_couleur($r, $gamma);
				$g = image_decal_couleur($g, $gamma);
				$b = image_decal_couleur($b, $gamma);

				$color = ImageColorAllocateAlpha( $im_, $r, $g, $b , $a );
				imagesetpixel ($im_, $x, $y, $color);			
			}
		}
		image_gd_output($im_,$image);
	}
	return image_ecrire_tag($image,array('src'=>$dest));
}

// Passe l'image en "sepia"
// On peut fixer les valeurs RVB 
// de la couleur "complementaire" pour forcer une dominante

// http://doc.spip.org/@image_decal_couleur_127
function image_decal_couleur_127 ($coul, $val) {
	if ($coul < 127) $y = round((($coul - 127) / 127) * $val) + $val;
	else if ($coul >= 127) $y = round((($coul - 127) / 128) * (255-$val)) + $val;
	else $y= $coul;
	
	if ($y < 0) $y = 0;
	if ($y > 255) $y = 255;
	return $y;
}
//function image_sepia($im, $dr = 137, $dv = 111, $db = 94)
// http://doc.spip.org/@image_sepia
function image_sepia($im, $rgb = "896f5e")
{
	
	if (!function_exists("imagecreatetruecolor")) return $im;
	
	$couleurs = couleur_hex_to_dec($rgb);
	$dr= $couleurs["red"];
	$dv= $couleurs["green"];
	$db= $couleurs["blue"];
		
	$fonction = array('image_sepia', func_get_args());
	$image = image_valeurs_trans($im, "sepia-$dr-$dv-$db",false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];
	
	if ($creer) {
		// Creation de l'image en deux temps
		// de facon a conserver les GIF transparents
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);
		imagecopy($im_, $im, 0, 0, 0, 0, $x_i, $y_i);
	
		for ($x = 0; $x < $x_i; $x++) {
			for ($y=0; $y < $y_i; $y++) {
				$rgb = ImageColorAt($im_, $x, $y);
				$a = ($rgb >> 24) & 0xFF;
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;

				$r = round(.299 * $r + .587 * $g + .114 * $b);
				$g = $r;
				$b = $r;


				$r = image_decal_couleur_127($r, $dr);
				$g = image_decal_couleur_127($g, $dv);
				$b = image_decal_couleur_127($b, $db);

				$color = ImageColorAllocateAlpha( $im_, $r, $g, $b , $a );
				imagesetpixel ($im_, $x, $y, $color);			
			}
		}
		image_gd_output($im_,$image);
		imagedestroy($im_);
		imagedestroy($im);
	}
	
	return image_ecrire_tag($image,array('src'=>$dest));
}


// Renforcer la nettete d'une image
// http://doc.spip.org/@image_renforcement
function image_renforcement($im, $k=0.5)
{
	$fonction = array('image_flou', func_get_args());
	$image = image_valeurs_trans($im, "renforcement-$k",false,$fonction);
	if (!$image) return("");
	
	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	$creer = $image["creer"];
	
	if ($creer) {
		$im = $image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		@imagealphablending($im_, false);
		@imagesavealpha($im_,true);
		$color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
		imagefill ($im_, 0, 0, $color_t);

		for ($x = 0; $x < $x_i; $x++) {
			for ($y=0; $y < $y_i; $y++) {		

                $rgb[1][0]=imagecolorat($im,$x,$y-1);
                $rgb[0][1]=imagecolorat($im,$x-1,$y);
                $rgb[1][1]=imagecolorat($im,$x,$y);
                $rgb[2][1]=imagecolorat($im,$x+1,$y);
                $rgb[1][2]=imagecolorat($im,$x,$y+1);
                
                
                if ($x-1 < 0) $rgb[0][1] = $rgb[1][1];
                if ($y-1 < 0) $rgb[1][0] = $rgb[1][1];
                if ($x+1 == $x_i) $rgb[2][1] = $rgb[1][1];
                if ($y+1 == $y_i) $rgb[1][2] = $rgb[1][1];

                $a = ($rgb[0][0] >> 24) & 0xFF;
                $r = -$k *(($rgb[1][0] >> 16) & 0xFF) +
                         -$k *(($rgb[0][1] >> 16) & 0xFF) +
                        (1+4*$k) *(($rgb[1][1] >> 16) & 0xFF) +
                         -$k *(($rgb[2][1] >> 16) & 0xFF) +
                         -$k *(($rgb[1][2] >> 16) & 0xFF) ;

                $g = -$k *(($rgb[1][0] >> 8) & 0xFF) +
                         -$k *(($rgb[0][1] >> 8) & 0xFF) +
                         (1+4*$k) *(($rgb[1][1] >> 8) & 0xFF) +
                         -$k *(($rgb[2][1] >> 8) & 0xFF) +
                         -$k *(($rgb[1][2] >> 8) & 0xFF) ;

                $b = -$k *($rgb[1][0] & 0xFF) +
                         -$k *($rgb[0][1] & 0xFF) +
                        (1+4*$k) *($rgb[1][1] & 0xFF) +
                         -$k *($rgb[2][1] & 0xFF) +
                         -$k *($rgb[1][2] & 0xFF) ;

                $r=min(255,max(0,$r));
                $g=min(255,max(0,$g));
                $b=min(255,max(0,$b));


		$color = ImageColorAllocateAlpha( $im_, $r, $g, $b , $a );
		imagesetpixel ($im_, $x, $y, $color);			
			}
		}		
		image_gd_output($im_,$image);
	}

	return image_ecrire_tag($image,array('src'=>$dest));
}


// Permet de regrouper deux images l'un a cote de l'autre dans un meme fichier
// la $dir est right, left, top ou bottom, pour le placement de l'image $masque par rapport a $im
function image_joindre ($im, $masque, $dir="right") {
	$masque = find_in_path($masque);
	$pos = md5(serialize($dir).@filemtime($masque));

	$fonction = array('image_joindre', func_get_args());
	$image = image_valeurs_trans($im, "joindre-$masque-$pos", "png", $fonction);
	if (!$image) return("");

	$mask = image_valeurs_trans($masque,"");
	if (!$mask) return("");

	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	$x_m = $mask["largeur"];
	$y_m = $mask["hauteur"];

	if ($dir == "right" OR $dir == "left") {
		$x_f = $x_i + $x_m;
		$y_f = max($y_i, $y_m);
	} else {
		$x_f = max($x_i, $x_m);
		$y_f = $y_i + $y_m;
	}
		
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];

	if ($creer) {
			$im_f = imagecreatetruecolor($x_f, $y_f);
			@imagealphablending($im_f, false);
			@imagesavealpha($im_f,true);
			$color_t = ImageColorAllocateAlpha( $im_f, 128, 128, 128 , 127 );
			imagefill ($im_f, 0, 0, $color_t);			
			$im1 = $image["fonction_imagecreatefrom"]($im);
			$im2 = $mask["fonction_imagecreatefrom"]($masque);

			if ($dir == "right") {			
				imagecopy ( $im_f, $im1, 0, 0, 0, 0, $x_i, $y_i);			
				imagecopy ( $im_f, $im2, $x_i, 0, 0, 0, $x_m, $y_m);			
			} else if ($dir == "left") {
				imagecopy ( $im_f, $im1, $x_m, 0, 0, 0, $x_i, $y_i);			
				imagecopy ( $im_f, $im2, 0, 0, 0, 0, $x_m, $y_m);			
			} else if ($dir == "bottom") {
				imagecopy ( $im_f, $im1, 0, 0, 0, 0, $x_i, $y_i);			
				imagecopy ( $im_f, $im2, 0, $y_i, 0, 0, $x_m, $y_m);			
			} else if ($dir == "top") {
				imagecopy ( $im_f, $im1, 0, $y_m, 0, 0, $x_i, $y_i);			
				imagecopy ( $im_f, $im2, 0, 0, 0, 0, $x_m, $y_m);			
			}

			image_gd_output($im_f,$image);
	}
	return image_ecrire_tag($image,array('src'=>$dest,'width'=>$x_f,'height'=>$y_f));
}


// 1/ Aplatir une image semi-transparente (supprimer couche alpha)
// en remplissant la transparence avec couleur choisir $coul.
// 2/ Forcer le format de sauvegarde (jpg, png, gif)
// pour le format jpg, $qualite correspond au niveau de compression (defaut 85)
// pour le format gif, $qualite correspond au nombre de couleurs dans la palette (defaut 128)
// pour le format png, $qualite correspond au nombre de couleur dans la palette ou si 0 a une image truecolor (defaut truecolor)
// attention, seul 128 est supporte en l'etat (production d'images avec palette reduite pas satisfaisante)
// http://doc.spip.org/@image_aplatir
// 3/ $transparence a "true" permet de conserver la transparence (utile pour conversion GIF)
// http://doc.spip.org/@image_aplatir
function image_aplatir($im, $format='jpg', $coul='000000', $qualite=NULL, $transparence=false)
{
	if ($qualite===NULL){
		if ($format=='jpg') $qualite=_IMG_GD_QUALITE;
		elseif ($format=='png') $qualite=0;
		else $qualite=128;
	}
	$fonction = array('image_aplatir', func_get_args());
	$image = image_valeurs_trans($im, "aplatir-$format-$coul-$qualite-$transparence", $format, $fonction);

	if (!$image) return("");

	include_spip('inc/filtres');
	$couleurs = couleur_hex_to_dec($coul);
	$dr= $couleurs["red"];
	$dv= $couleurs["green"];
	$db= $couleurs["blue"];

	$x_i = $image["largeur"];
	$y_i = $image["hauteur"];
	
	$im = $image["fichier"];
	$dest = $image["fichier_dest"];
	
	$creer = $image["creer"];

	if ($creer) {
		$im = @$image["fonction_imagecreatefrom"]($im);
		imagepalettetotruecolor($im);
		$im_ = imagecreatetruecolor($x_i, $y_i);
		if ($image["format_source"] == "gif" AND function_exists('ImageCopyResampled')) { 
			// Si un GIF est transparent, 
			// fabriquer un PNG transparent  
			// Conserver la transparence 
			@imagealphablending($im_, false); 
			@imagesavealpha($im_,true); 
			if (function_exists("imageAntiAlias")) imageAntiAlias($im_,true); 
			@ImageCopyResampled($im_, $im, 0, 0, 0, 0, $x_i, $y_i, $x_i, $y_i);
			imagedestroy($im);
			$im = $im_;
		}
		
		// allouer la couleur de fond
		if ($transparence) {
			@imagealphablending($im_, false); 
			@imagesavealpha($im_,true); 
			$color_t = imagecolorallocatealpha( $im_, $dr, $dv, $db, 127);
		}
		else $color_t = ImageColorAllocate( $im_, $dr, $dv, $db);
		
		imagefill ($im_, 0, 0, $color_t);

		//??
		//$dist = abs($trait);
		
		$transp_x = false;
		
		for ($x = 0; $x < $x_i; $x++) {
			for ($y=0; $y < $y_i; $y++) {
			
				$rgb = ImageColorAt($im, $x, $y);
				$a = ($rgb >> 24) & 0xFF;
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;

				$a = (127-$a) / 127;
				
				if ($a == 1) { // Limiter calculs
					$r = $r;
					$g = $g;
					$b = $b;
				}
				else if ($a == 0) { // Limiter calculs
					$r = $dr;
					$g = $dv;
					$b = $db;
					
					$transp_x = $x; // Memoriser un point transparent
					$transp_y = $y;
					
				} else {
					$r = round($a * $r + $dr * (1-$a));
					$g = round($a * $g + $dv * (1-$a));
					$b = round($a * $b + $db * (1-$a));
				}
				$a = (1-$a) *127;
				$color = ImageColorAllocateAlpha( $im_, $r, $g, $b, $a);
				imagesetpixel ($im_, $x, $y, $color);	
			}
		}
		// passer en palette si besoin
		if ($format=='gif' OR ($format=='png' AND $qualite!==0)){
			// creer l'image finale a palette (on recycle l'image initiale)			


			@imagetruecolortopalette($im,true,$qualite);


			//$im = imagecreate($x_i, $y_i);
			// copier l'image true color vers la palette
			imagecopy($im, $im_, 0, 0, 0, 0, $x_i, $y_i);
			// matcher les couleurs au mieux par rapport a l'image initiale
			// si la fonction est disponible (php>=4.3)
			if (function_exists('imagecolormatch'))
				@imagecolormatch($im_, $im);
				
			if ($format=='gif' && $transparence && $transp_x) {	
				$color_t = ImagecolorAt( $im, $transp_x, $transp_y);
				if ($format == "gif" && $transparence) @imagecolortransparent($im, $color_t);
			}
				
				
			// produire le resultat
			image_gd_output($im, $image, $qualite);
		}
		else
			image_gd_output($im_, $image, $qualite);
		imagedestroy($im_);
		imagedestroy($im);
	}
	return image_ecrire_tag($image,array('src'=>$dest));
}


// Enregistrer une image dans un format donne
// (conserve la transparence gif, png, ico)
// utilise [->@image_aplatir]
// http://doc.spip.org/@image_format
function image_format($img, $format='png') {
	$qualite = null;
	if ($format=='png8') {$format='png';$qualite=128;}
	return image_aplatir($img, $format, 'cccccc', $qualite, true);
}



// A partir d'une image,
// recupere une couleur
// renvoit sous la forme hexadecimale ("F26C4E" par exemple).
// Par defaut, la couleur choisie se trouve un peu au-dessus du centre de l'image.
// On peut forcer un point en fixant $x et $y, entre 0 et 20.
// http://doc.spip.org/@image_couleur_extraire
function image_couleur_extraire($img, $x=10, $y=6) {

	$cache = image_valeurs_trans($img, "coul-$x-$y", "php");
	if (!$cache) return "F26C4E";
	
	$fichier = $cache["fichier"];
	$dest = $cache["fichier_dest"];
	$terminaison = $cache["format_source"];
	
	$creer = $cache["creer"];
	if ($creer) {
		if (!$GLOBALS["couleur_extraite"]["$fichier-$x-$y"]) {	
			if (file_exists($fichier)) {
				list($width, $height) = getimagesize($fichier);
			
			
				$newwidth = 20;
				$newheight = 20;
			
				$thumb = imagecreate($newwidth, $newheight);

				if (preg_match(",\.jpe?g$,i", $fichier)) $source = imagecreatefromjpeg($fichier);
				if (preg_match(",\.gif$,i", $fichier)) $source = imagecreatefromgif($fichier);
				if (preg_match(",\.png$,i", $fichier)) $source = imagecreatefrompng($fichier);
				imagepalettetotruecolor($source);

				imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
			
				// get a color
				$color_index = imagecolorat($thumb, $x, $y);
				
				// make it human readable
				$color_tran = imagecolorsforindex($thumb, $color_index);
				
				$couleur = couleur_dec_to_hex($color_tran["red"], $color_tran["green"], $color_tran["blue"]);
			}
			else {
				$couleur = "F26C4E";
			}
			$GLOBALS["couleur_extraite"]["$fichier-$x-$y"] = $couleur;

			$handle = fopen($dest, 'w');
			fwrite($handle, "<"."?php \$GLOBALS[\"couleur_extraite\"][\"".$fichier."-".$x."-".$y."\"] = \"".$couleur."\"; ?".">");
			fclose($handle);
		
		}
		// Mettre en cache le resultat
		
	} else {
		include("$dest");
	}
	
	
	return $GLOBALS["couleur_extraite"]["$fichier-$x-$y"];
}

// http://doc.spip.org/@couleur_html_to_hex
function couleur_html_to_hex($couleur){
	$couleurs_html=array(
		'aqua'=>'00FFFF','black'=>'000000','blue'=>'0000FF','fuchsia'=>'FF00FF','gray'=>'808080','green'=>'008000','lime'=>'00FF00','maroon'=>'800000',
		'navy'=>'000080','olive'=>'808000','purple'=>'800080','red'=>'FF0000','silver'=>'C0C0C0','teal'=>'008080','white'=>'FFFFFF','yellow'=>'FFFF00');
	if (isset($couleurs_html[$lc=strtolower($couleur)]))
		return $couleurs_html[$lc];
	return $couleur;
}

// http://doc.spip.org/@couleur_dec_to_hex
function couleur_dec_to_hex($red, $green, $blue) {
	$red = dechex($red);
	$green = dechex($green);
	$blue = dechex($blue);
	
	if (strlen($red) == 1) $red = "0".$red;
	if (strlen($green) == 1) $green = "0".$green;
	if (strlen($blue) == 1) $blue = "0".$blue;
	
	return "$red$green$blue";
}

// http://doc.spip.org/@couleur_hex_to_dec
function couleur_hex_to_dec($couleur) {
	$couleur = couleur_html_to_hex($couleur);
	$couleur = preg_replace(",^#,","",$couleur);
	$retour["red"] = hexdec(substr($couleur, 0, 2));
	$retour["green"] = hexdec(substr($couleur, 2, 2));
	$retour["blue"] = hexdec(substr($couleur, 4, 2));
	
	return $retour;
}

// http://doc.spip.org/@couleur_multiple_de_trois
function couleur_multiple_de_trois($val) {
	$val = hexdec($val);
	$val = round($val / 3) * 3;
	$val = dechex($val);
	return $val;
	
}

// http://doc.spip.org/@couleur_web
function couleur_web($couleur) {
	$r = couleur_multiple_de_trois(substr($couleur, 0, 1));
	$v = couleur_multiple_de_trois(substr($couleur, 2, 1));
	$b = couleur_multiple_de_trois(substr($couleur, 4, 1));
	
	return "$r$r$v$v$b$b";
}

// http://doc.spip.org/@couleur_4096
function couleur_4096($couleur) {
	$r = (substr($couleur, 0, 1));
	$v = (substr($couleur, 2, 1));
	$b = (substr($couleur, 4, 1));
	
	return "$r$r$v$v$b$b";
}


// http://doc.spip.org/@couleur_extreme
function couleur_extreme ($couleur, $limite=0.5) {
	// force la couleur au noir ou au blanc le plus proche
	// -> donc couleur foncee devient noire
	//    et couleur claire devient blanche
	// -> la limite est une valeur de 0 a 255, permettant de regler le point limite entre le passage noir ou blanc

	$couleurs = couleur_hex_to_dec($couleur);
	$red = $couleurs["red"];
	$green = $couleurs["green"];
	$blue = $couleurs["blue"];
	
	
	/*	
	$moyenne = round(($red+$green+$blue)/3);

	if ($moyenne > $limite) $couleur_texte = "ffffff";
	else $couleur_texte = "000000";
	*/

	$hsl = couleur_rgb2hsl ($red, $green, $blue);

	if ($hsl["l"] > $limite) $couleur_texte = "ffffff";
	else $couleur_texte = "000000";

	return $couleur_texte;
}

// http://doc.spip.org/@couleur_inverser
function couleur_inverser ($couleur) {
	$couleurs = couleur_hex_to_dec($couleur);
	$red = 255 - $couleurs["red"];
	$green = 255 - $couleurs["green"];
	$blue = 255 - $couleurs["blue"];

	$couleur = couleur_dec_to_hex($red, $green, $blue);
	
	return $couleur;
}

// http://doc.spip.org/@couleur_eclaircir
function couleur_eclaircir ($couleur) {
	$couleurs = couleur_hex_to_dec($couleur);

	$red = $couleurs["red"] + round((255 - $couleurs["red"])/2);
	$green = $couleurs["green"] + round((255 - $couleurs["green"])/2);
	$blue = $couleurs["blue"] + round((255 - $couleurs["blue"])/2);

	$couleur = couleur_dec_to_hex($red, $green, $blue);
	
	return $couleur;

}
// http://doc.spip.org/@couleur_foncer
function couleur_foncer ($couleur) {
	$couleurs = couleur_hex_to_dec($couleur);

	$red = $couleurs["red"] - round(($couleurs["red"])/2);
	$green = $couleurs["green"] - round(($couleurs["green"])/2);
	$blue = $couleurs["blue"] - round(($couleurs["blue"])/2);

	$couleur = couleur_dec_to_hex($red, $green, $blue);
	
	return $couleur;
}
// http://doc.spip.org/@couleur_foncer_si_claire
function couleur_foncer_si_claire ($couleur) {
	// ne foncer que les couleurs claires
	// utile pour ecrire sur fond blanc, 
	// mais sans changer quand la couleur est deja foncee
	$couleurs = couleur_hex_to_dec($couleur);
	$red = $couleurs["red"];
	$green = $couleurs["green"];
	$blue = $couleurs["blue"];
	
	$moyenne = round(($red+$green+$blue)/3);
	
	if ($moyenne > 122) return couleur_foncer($couleur);
	else return $couleur;
}
// http://doc.spip.org/@couleur_eclaircir_si_foncee
function couleur_eclaircir_si_foncee ($couleur) {
	$couleurs = couleur_hex_to_dec($couleur);
	$red = $couleurs["red"];
	$green = $couleurs["green"];
	$blue = $couleurs["blue"];
	
	$moyenne = round(($red+$green+$blue)/3);
	
	if ($moyenne < 123) return couleur_eclaircir($couleur);
	else return $couleur;
}


// http://doc.spip.org/@couleur_saturation
function couleur_saturation($couleur, $val) {
	if ($couleur == "ffffff") $couleur = "eeeeee";

	$couleurs = couleur_hex_to_dec($couleur);
	$r= 255 - $couleurs["red"];
	$g= 255 - $couleurs["green"];
	$b= 255 - $couleurs["blue"];

	$max = max($r,$g,$b);

	$r = 255 - $r / $max * 255 * $val;
	$g = 255 - $g / $max * 255 * $val;
	$b = 255 - $b / $max * 255 * $val;
	
	$couleur = couleur_dec_to_hex($r, $g, $b);
	
	return $couleur;
		
}



// http://doc.spip.org/@couleur_rgb2hsv
function couleur_rgb2hsv ($R,$G,$B) {
	$var_R = ( $R / 255 ) ;                    //Where RGB values = 0 ÷ 255
	$var_G = ( $G / 255 );
	$var_B = ( $B / 255 );

	$var_Min = min( $var_R, $var_G, $var_B ) ;   //Min. value of RGB
	$var_Max = max( $var_R, $var_G, $var_B ) ;   //Max. value of RGB
	$del_Max = $var_Max - $var_Min  ;           //Delta RGB value

	$V = $var_Max;
	$L = ( $var_Max + $var_Min ) / 2;
	
	if ( $del_Max == 0 )                     //This is a gray, no chroma...
	{
	   $H = 0 ;                            //HSL results = 0 ÷ 1
	   $S = 0 ;
	}
	else                                    //Chromatic data...
	{
	   $S = $del_Max / $var_Max;
	
	   $del_R = ( ( ( $var_Max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
	   $del_G = ( ( ( $var_Max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
	   $del_B = ( ( ( $var_Max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
	
	   if      ( $var_R == $var_Max ) $H = $del_B - $del_G;
	   else if ( $var_G == $var_Max ) $H = ( 1 / 3 ) + $del_R - $del_B;
	   else if ( $var_B == $var_Max ) $H = ( 2 / 3 ) + $del_G - $del_R;
	
	   if ( $H < 0 )  $H =  $H + 1;
	   if ( $H > 1 )  $H = $H - 1;
	}
				
	$ret["h"] = $H;
	$ret["s"] = $S;
	$ret["v"] = $V;
	
	return $ret;
}


// http://doc.spip.org/@couleur_hsv2rgb
function couleur_hsv2rgb ($H,$S,$V) {
	
	if ( $S == 0 )                       //HSV values = 0 ÷ 1
	{
	   $R = $V * 255;
	   $G = $V * 255;
	   $B = $V * 255;
	}
	else
	{
	   $var_h = $H * 6;
	   if ( $var_h == 6 ) $var_h = 0 ;     //H must be < 1
	   $var_i = floor( $var_h )  ;           //Or ... var_i = floor( var_h )
	   $var_1 = $V * ( 1 - $S );
	   $var_2 = $V * ( 1 - $S * ( $var_h - $var_i ) );
	   $var_3 = $V * ( 1 - $S * ( 1 - ( $var_h - $var_i ) ) );
	
	
	   if      ( $var_i == 0 ) { $var_r = $V     ; $var_g = $var_3 ; $var_b = $var_1 ; }
	   else if ( $var_i == 1 ) { $var_r = $var_2 ; $var_g = $V     ; $var_b = $var_1 ; }
	   else if ( $var_i == 2 ) { $var_r = $var_1 ; $var_g = $V     ; $var_b = $var_3 ; }
	   else if ( $var_i == 3 ) { $var_r = $var_1 ; $var_g = $var_2 ; $var_b = $V ;     }
	   else if ( $var_i == 4 ) { $var_r = $var_3 ; $var_g = $var_1 ; $var_b = $V ; }
	   else                   { $var_r = $V     ; $var_g = $var_1 ; $var_b = $var_2; }
	
	   $R = $var_r * 255;                  //RGB results = 0 ÷ 255
	   $G = $var_g * 255;
	   $B = $var_b * 255;
	}
	$ret["r"] = floor($R);
	$ret["g"] = floor($G);
	$ret["b"] = floor($B);
	
	return $ret;
}


// http://doc.spip.org/@couleur_rgb2hsl
function couleur_rgb2hsl ($R,$G,$B) {
	$var_R = ( $R / 255 ) ;                    //Where RGB values = 0 ÷ 255
	$var_G = ( $G / 255 );
	$var_B = ( $B / 255 );

	$var_Min = min( $var_R, $var_G, $var_B ) ;   //Min. value of RGB
	$var_Max = max( $var_R, $var_G, $var_B ) ;   //Max. value of RGB
	$del_Max = $var_Max - $var_Min  ;           //Delta RGB value

	$L = ( $var_Max + $var_Min ) / 2;
	
	if ( $del_Max == 0 )                     //This is a gray, no chroma...
	{
	   $H = 0 ;                            //HSL results = 0 ÷ 1
	   $S = 0 ;
	}
	else                                    //Chromatic data...
	{
		if ($L < 0.5 ) $S = $del_Max / ( $var_Max+ $var_Min);
		else $S = $del_Max/ ( 2 - $var_Max - $var_Min);

		$del_R = ( ( ( $var_Max- $var_R) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
		$del_G = ( ( ( $var_Max- $var_G) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
		$del_B = ( ( ( $var_Max- $var_B) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;

		if ( $var_R == $var_Max) $H= $del_B - $del_G;
		else if ( $var_G == $var_Max) $H= ( 1 / 3 ) + $del_R - $del_B;
		else if ( $var_B == $var_Max) $H= ( 2 / 3 ) + $del_G - $del_R;

		if ( $H < 0 ) $H+= 1;
		if ( $H > 1 ) $H-= 1;
	}
				
	$ret["h"] = $H;
	$ret["s"] = $S;
	$ret["l"] = $L;
	
	return $ret;
}


// http://doc.spip.org/@hue_2_rgb
function hue_2_rgb( $v1, $v2, $vH ) {
   if ( $vH < 0 ) $vH += 1;
   if ( $vH > 1 ) $vH -= 1;
   if ( ( 6 * $vH ) < 1 ) return ( $v1 + ( $v2 - $v1 ) * 6 * $vH );
   if ( ( 2 * $vH ) < 1 ) return ( $v2 );
   if ( ( 3 * $vH ) < 2 ) return ( $v1 + ( $v2 - $v1 ) * ( ( 2 / 3 ) - $vH ) * 6 );
   return ( $v1 );
}

// http://doc.spip.org/@couleur_hsl2rgb
function couleur_hsl2rgb ($H,$S,$L) {
	
	if ( $S == 0 )                       //HSV values = 0 ÷ 1
	{
	   $R = $V * 255;
	   $G = $V * 255;
	   $B = $V * 255;
	}
	else
	{
		if ( $L < 0.5 ) $var_2 = $L * ( 1 + $S );
		else            $var_2 = ( $L + $S ) - ( $S * $L );

		$var_1 = 2 * $L - $var_2;

		$R = 255 * hue_2_rgb( $var_1, $var_2, $H + ( 1 / 3 ) ) ;
		$G = 255 * hue_2_rgb( $var_1, $var_2, $H );
		$B = 255 * hue_2_rgb( $var_1, $var_2, $H - ( 1 / 3 ) );
	}
	$ret["r"] = floor($R);
	$ret["g"] = floor($G);
	$ret["b"] = floor($B);
	
	return $ret;
}




// Image typographique

// Fonctions pour l'arabe


// http://doc.spip.org/@rtl_mb_ord
function rtl_mb_ord($char){

	if (($c = ord($char)) < 216) return $c;
	else return 256 * rtl_mb_ord(substr($char, 0, -1)) + ord(substr($char, -1));

/*	return (strlen($char) < 2) ?
		ord($char) : 256 * mb_ord(substr($char, 0, -1))
			+ ord(substr($char, -1));
			
*/			
  }



// http://doc.spip.org/@rtl_reverse
function rtl_reverse($mot, $rtl_global) {
	$rtl_prec = $rtl_global;

	$ponctuations = array("/", "-", "«","»", "“", "”", ",", ".", " ", ":", ";", "(", ")", "،", "؟", "?", "!", " ");
	foreach($ponctuations as $ponct) {
		$ponctuation[$ponct] = true;
	}

		

	for ($i = 0; $i < spip_strlen($mot); $i++) {
		$lettre = spip_substr($mot, $i, 1);
		
		
		$code = rtl_mb_ord($lettre);
//		echo "<li>$lettre - $code";

		
//			echo "<li>$code";
		if (($code >= 54928 && $code <= 56767) ||  ($code >= 15707294 && $code <= 15711164)) {
			$rtl = true;
		}
		else $rtl = false;
		
		if ($lettre == "٠" || $lettre == "١" || $lettre == "٢" || $lettre == "٣" || $lettre == "٤" || $lettre == "٥"
				 || $lettre == "٦" || $lettre == "٧" || $lettre == "٨" || $lettre == "٩") $rtl = false;
		
		if ($ponctuation[$lettre]) {
			$rtl = $rtl_prec;
			
			if ($rtl) {
				switch ($lettre) {
					case "(": $lettre = ")"; break;
					case ")": $lettre = "("; break;
					case "«": $lettre = "»"; break;
					case "»": $lettre = "«"; break;
					case "“": $lettre = "”"; break;
					case "”": $lettre = "“"; break;
				}
			}
		}
		
		
		if ($rtl) $res = $lettre.$res;
		else $res = $res.$lettre;
		
		$rtl_prec = $rtl;
		
	}
	return $res;
}



// http://doc.spip.org/@rtl_visuel
function rtl_visuel($texte, $rtl_global) {
	// hebreu + arabe: 54928 => 56767
	// hebreu + presentation A: 15707294 => 15710140
	// arabe presentation: 15708336 => 15711164
	
//	echo hexdec("efb7bc");

	// premiere passe pour determiner s'il y a du rtl
	// de facon a placer ponctuation et mettre les mots dans l'ordre
	
	/*
	if ($rtl_global) {
		$texte = ereg_replace("([\-])", "^\\1^", $texte);
		if (ereg("\^", $texte) {
			$texte = explode("^", $texte);
			foreach($texte as $part) {
				$total .= rtl_visuel($part, $rtl_global);
			}
			return $total;
		}
	}
	*/
	

	$arabic_letters = array(
		array("ي", // lettre 0
			"ﻱ",  // isolee 1
			"ﻳ", // debut 2
			"ﻴ", // milieu 3
			"ﻲ"),
		array("ب", // lettre 0
			"ﺏ",  // isolee 1
			"ﺑ", // debut 2
			"ﺒ", // milieu 3
			"ﺐ"),
		array("ا", // lettre 0
			"ا",  // isolee 1
			"ﺍ", // debut 2
			"ﺍ", // milieu 3
			"ﺎ"),
		array("إ", // lettre 0
			"إ",  // isolee 1
			"إ", // debut 2
			"ﺈ", // milieu 3
			"ﺈ"),
		array("ل", // lettre 0
			"ﻝ",  // isolee 1
			"ﻟ", // debut 2
			"ﻠ", // milieu 3
			"ﻞ"),
		array("خ", // lettre 0
			"ﺥ",  // isolee 1
			"ﺧ", // debut 2
			"ﺨ", // milieu 3
			"ﺦ"),
		array("ج", // lettre 0
			"ﺝ",  // isolee 1
			"ﺟ", // debut 2
			"ﺠ", // milieu 3
			"ﺞ"),
		array("س", // lettre 0
			"ﺱ",  // isolee 1
			"ﺳ", // debut 2
			"ﺴ", // milieu 3
			"ﺲ"),
		array("ن", // lettre 0
			"ﻥ",  // isolee 1
			"ﻧ", // debut 2
			"ﻨ", // milieu 3
			"ﻦ"),
		array("ش", // lettre 0
			"ﺵ",  // isolee 1
			"ﺷ", // debut 2
			"ﺸ", // milieu 3
			"ﺶ"),
		array("ق", // lettre 0
			"ﻕ",  // isolee 1
			"ﻗ", // debut 2
			"ﻘ", // milieu 3
			"ﻖ"),
		array("ح", // lettre 0
			"ﺡ",  // isolee 1
			"ﺣ", // debut 2
			"ﺤ", // milieu 3
			"ﺢ"),
		array("م", // lettre 0
			"ﻡ",  // isolee 1
			"ﻣ", // debut 2
			"ﻤ", // milieu 3
			"ﻢ"),
		array("ر", // lettre 0
			"ر",  // isolee 1
			"ﺭ", // debut 2
			"ﺮ", // milieu 3
			"ﺮ"),
		array("ع", // lettre 0
			"ع",  // isolee 1
			"ﻋ", // debut 2
			"ﻌ", // milieu 3
			"ﻊ"),
		array("و", // lettre 0
			"و",  // isolee 1
			"ﻭ", // debut 2
			"ﻮ", // milieu 3
			"ﻮ"),
		array("ة", // lettre 0
			"ة",  // isolee 1
			"ة", // debut 2
			"ﺔ", // milieu 3
			"ﺔ"),
		array("ف", // lettre 0
			"ﻑ",  // isolee 1
			"ﻓ", // debut 2
			"ﻔ", // milieu 3
			"ﻒ"),
		array("ﻻ", // lettre 0
			"ﻻ",  // isolee 1
			"ﻻ", // debut 2
			"ﻼ", // milieu 3
			"ﻼ"),
		array("ح", // lettre 0
			"ﺡ",  // isolee 1
			"ﺣ", // debut 2
			"ﺤ", // milieu 3
			"ﺢ"),
		array("ت", // lettre 0
			"ﺕ",  // isolee 1
			"ﺗ", // debut 2
			"ﺘ", // milieu 3
			"ﺖ"),
		array("ض", // lettre 0
			"ﺽ",  // isolee 1
			"ﺿ", // debut 2
			"ﻀ", // milieu 3
			"ﺾ"),
		array("ك", // lettre 0
			"ك",  // isolee 1
			"ﻛ", // debut 2
			"ﻜ", // milieu 3
			"ﻚ"),
		array("ه", // lettre 0
			"ﻩ",  // isolee 1
			"ﻫ", // debut 2
			"ﻬ", // milieu 3
			"ﻪ"),
		array("ي", // lettre 0
			"ي",  // isolee 1
			"ﻳ", // debut 2
			"ﻴ", // milieu 3
			"ﻲ"),
		array("ئ", // lettre 0
			"ﺉ",  // isolee 1
			"ﺋ", // debut 2
			"ﺌ", // milieu 3
			"ﺊ"),
		array("ص", // lettre 0
			"ﺹ",  // isolee 1
			"ﺻ", // debut 2
			"ﺼ", // milieu 3
			"ﺺ"),
		array("ث", // lettre 0
			"ﺙ",  // isolee 1
			"ﺛ", // debut 2
			"ﺜ", // milieu 3
			"ﺚ"),
		array("ﻷ", // lettre 0
			"ﻷ",  // isolee 1
			"ﻷ", // debut 2
			"ﻸ", // milieu 3
			"ﻸ"),
		array("د", // lettre 0
			"ﺩ",  // isolee 1
			"ﺩ", // debut 2
			"ﺪ", // milieu 3
			"ﺪ"),
		array("ذ", // lettre 0
			"ﺫ",  // isolee 1
			"ﺫ", // debut 2
			"ﺬ", // milieu 3
			"ﺬ"),
		array("ط", // lettre 0
			"ﻁ",  // isolee 1
			"ﻃ", // debut 2
			"ﻄ", // milieu 3
			"ﻂ"),
		array("آ", // lettre 0
			"آ",  // isolee 1
			"آ", // debut 2
			"ﺂ", // milieu 3
			"ﺂ"),
		array("أ", // lettre 0
			"أ",  // isolee 1
			"أ", // debut 2
			"ﺄ", // milieu 3
			"ﺄ"),
		array("ؤ", // lettre 0
			"ؤ",  // isolee 1
			"ؤ", // debut 2
			"ﺆ", // milieu 3
			"ﺆ"),
		array("ز", // lettre 0
			"ز",  // isolee 1
			"ز", // debut 2
			"ﺰ", // milieu 3
			"ﺰ"),
		array("ظ", // lettre 0
			"ظ",  // isolee 1
			"ﻇ", // debut 2
			"ﻈ", // milieu 3
			"ﻆ"),
		array("غ", // lettre 0
			"غ",  // isolee 1
			"ﻏ", // debut 2
			"ﻐ", // milieu 3
			"ﻎ"),
		array("ى", // lettre 0
			"ى",  // isolee 1
			"ﯨ", // debut 2
			"ﯩ", // milieu 3
			"ﻰ"),
		array("پ", // lettre 0
			"پ",  // isolee 1
			"ﭘ", // debut 2
			"ﭙ", // milieu 3
			"ﭗ"),
		array("چ", // lettre 0
			"چ",  // isolee 1
			"ﭼ", // debut 2
			"ﭽ", // milieu 3
			"ﭻ")
	);
	
	if(init_mb_string() AND mb_regex_encoding() !== "UTF-8") echo "Attention: dans php.ini, il faut indiquer:<br /><strong>mbstring.internal_encoding = UTF-8</strong>";
	
	
	$texte = explode(" ", $texte);
	
	foreach ($texte as $mot) {
		$res = "";



		// Inserer des indicateurs de debut/fin
		$mot = "^".$mot."^";

		$mot = preg_replace(",&nbsp;,u", " ", $mot);
		$mot = preg_replace(",&#171;,u", "«", $mot);
		$mot = preg_replace(",&#187;,u", "»", $mot);




		// ponctuations
		$ponctuations = array("/", "-", "«","»", "“", "”", ",", ".", " ", ":", ";", "(", ")", "،", "؟", "?", "!"," ");
		foreach($ponctuations as $ponct) {
			$mot = str_replace("$ponct", "^$ponct^", $mot);
		}
		// lettres forcant coupure
		$mot = preg_replace(",ا,u", "ا^", $mot);
		$mot = preg_replace(",د,u", "د^", $mot);
		$mot = preg_replace(",أ,u", "أ^", $mot);
		$mot = preg_replace(",إ,u", "إ^", $mot);
		$mot = preg_replace(",أ,u", "أ^", $mot);
		$mot = preg_replace(",ر,u", "ر^", $mot);
		$mot = preg_replace(",ذ,u", "ذ^", $mot);
		$mot = preg_replace(",ز,u", "ز^", $mot);
		$mot = preg_replace(",و,u", "و^", $mot);
		$mot = preg_replace(",و,u", "و^", $mot);
		$mot = preg_replace(",ؤ,u", "ؤ^", $mot);
		$mot = preg_replace(",ة,u", "ة^", $mot);
		//		$mot = preg_replace(",ل,u", "^ل", $mot);
		//		$mot = preg_replace(",,", "^", $mot);


		$mot = preg_replace(",٠,u", "^٠^", $mot);
		$mot = preg_replace(",١,u", "^١^", $mot);
		$mot = preg_replace(",٢,u", "^٢^", $mot);
		$mot = preg_replace(",٣,u", "^٣^", $mot);
		$mot = preg_replace(",٤,u", "^٤^", $mot);
		$mot = preg_replace(",٥,u", "^٥^", $mot);
		$mot = preg_replace(",٦,u", "^٦^", $mot);
		$mot = preg_replace(",٧,u", "^٧^", $mot);
		$mot = preg_replace(",٨,u", "^٨^", $mot);
		$mot = preg_replace(",٩,u", "^٩^", $mot);

		
		// accents (enfin, pas exactement)
				
		$mot = preg_replace(",\^ّ,u", "ّ^", $mot);
		$mot = preg_replace(",\^ْ,u", "ْ^", $mot);
		$mot = preg_replace(",\^ِ,u", "ِ^", $mot);
		$mot = preg_replace(",\^َ,u", "َ^", $mot);
		$mot = preg_replace(",\^ً,u", "ً^", $mot);
		$mot = preg_replace(",\^ٍ,u", "ٍ^", $mot);
		$mot = preg_replace(",\^ُ,u", "ُ^", $mot);
		$mot = preg_replace(",\^ٌ,u", "ٌ^", $mot);
	

		// Ligatures
		$mot = preg_replace(",لا,u", "ﻻ", $mot);
		$mot = preg_replace(",لأ,u", "ﻷ", $mot);
		
		
		
		foreach ($arabic_letters as $a_l) {
			$mot = preg_replace(",([^\^])".$a_l[0]."([^\^]),u", "\\1".$a_l[3]."\\2", $mot);
			$mot = preg_replace(",\^".$a_l[0]."([^\^]),u", "^".$a_l[2]."\\1", $mot);
			$mot = preg_replace(",([^\^])".$a_l[0]."\^,u", "\\1".$a_l[4]."^", $mot);
			// il semble qu'il ne soit pas necessaire de remplacer
			// la lettre isolee
			//			$mot = preg_replace(",\^".$a_l[0]."\^,u", "^".$a_l[1]."^", $mot);
		}
		
		

		$mot = preg_replace(",\^,u", "", $mot);
		
		$res = $mot;
		$res = rtl_reverse($mot, $rtl_global);

		/*
		$rtl = false;		
		for ($i = 0; $i < spip_strlen($mot); $i++) {
			$lettre = spip_substr($mot, $i, 1);
			$code = rtl_mb_ord($lettre);
			if (($code >= 54928 && $code <= 56767) ||  ($code >= 15708336 && $code <= 15711164)) $rtl = true;
		}
		*/
		
		
		if ($rtl_global) $retour = $res . " " . $retour;
		else $retour = $retour. " ".$res;
	}
	
	
	return $retour;
}




// http://doc.spip.org/@printWordWrapped
function printWordWrapped($image, $top, $left, $maxWidth, $font, $couleur, $text, $textSize, $align="left", $hauteur_ligne = 0) {
	static $memps = array();

	// imageftbbox exige un float, et settype aime le double pour php < 4.2.0
	settype($textSize, 'double');

	// calculer les couleurs ici, car fonctionnement different selon TTF ou PS
	$black = imagecolorallocatealpha($image, hexdec("0x{".substr($couleur, 0,2)."}"), hexdec("0x{".substr($couleur, 2,2)."}"), hexdec("0x{".substr($couleur, 4,2)."}"), 0);
	$grey2 = imagecolorallocatealpha($image, hexdec("0x{".substr($couleur, 0,2)."}"), hexdec("0x{".substr($couleur, 2,2)."}"), hexdec("0x{".substr($couleur, 4,2)."}"), 127);

	// Gaffe, T1Lib ne fonctionne carrement pas bien des qu'on sort de ASCII
	// C'est dommage, parce que la rasterisation des caracteres est autrement plus jolie qu'avec TTF.
	// A garder sous le coude en attendant que ca ne soit plus une grosse bouse.
	// Si police Postscript et que fonction existe...
	if (
	false AND
	strtolower(substr($font,-4)) == ".pfb"
	AND function_exists("imagepstext")) {
		// Traitement specifique pour polices PostScript (experimental)
		$textSizePs = round(1.32 * $textSize);
		if (!$fontps = $memps["$font"]) {
			$fontps = imagepsloadfont($font);
			// Est-ce qu'il faut reencoder? Pas testable proprement, alors... 
			// imagepsencodefont($fontps,find_in_path('polices/standard.enc'));
			$memps["$font"] = $fontps;
		}
	}

	$rtl_global = false;
	for ($i = 0; $i < spip_strlen($text); $i++) {
		$lettre = spip_substr($text, $i, 1);
		$code = rtl_mb_ord($lettre);
		if (($code >= 54928 && $code <= 56767) ||  ($code >= 15707294 && $code <= 15711164)) {
			$rtl_global = true;
		}
	}


	// split the text into an array of single words
	$words = explode(' ', $text);

	// les espaces
	foreach($words as $k=>$v)
		$words[$k] = str_replace(array('~'), array(' '), $v);


	if ($hauteur_ligne == 0) $lineHeight = floor($textSize * 1.3);
	else $lineHeight = $hauteur_ligne;

	$dimensions_espace = imageftbbox($textSize, 0, $font, ' ', array());
	$largeur_espace = $dimensions_espace[2] - $dimensions_espace[0];
	$retour["espace"] = $largeur_espace;


	$line = '';
	while (count($words) > 0) {
		
		$mot = $words[0];
		
		if ($rtl_global) $mot = rtl_visuel($mot,$rtl_global);
	
		$dimensions = imageftbbox($textSize, 0, $font, $line.' '.$mot, array());
		$lineWidth = $dimensions[2] - $dimensions[0]; // get the length of this line, if the word is to be included
		if ($lineWidth > $maxWidth) { // if this makes the text wider that anticipated
			$lines[] = $line; // add the line to the others
			$line = ''; // empty it (the word will be added outside the loop)
		}
		$line .= ' '.$words[0]; // add the word to the current sentence
		$words = array_slice($words, 1); // remove the word from the array
	}
	if ($line != '') { $lines[] = $line; } // add the last line to the others, if it isn't empty
	$height = count($lines) * $lineHeight; // the height of all the lines total
	// do the actual printing
	$i = 0;

	// Deux passes pour recuperer, d'abord, largeur_ligne
	// necessaire pour alignement right et center
	foreach ($lines as $line) {
		if ($rtl_global) $line = rtl_visuel($line, $rtl_global);
		
		$dimensions = imageftbbox($textSize, 0, $font, $line, array());
		$largeur_ligne = $dimensions[2] - $dimensions[0];
		if ($largeur_ligne > $largeur_max) $largeur_max = $largeur_ligne;
	}

	foreach ($lines as $i => $line) {
		if ($rtl_global) $line = rtl_visuel($line, $rtl_global);

		$dimensions = imageftbbox($textSize, 0, $font, $line, array());
		$largeur_ligne = $dimensions[2] - $dimensions[0];
		if ($align == "right") $left_pos = $largeur_max - $largeur_ligne;
		else if ($align == "center") $left_pos = floor(($largeur_max - $largeur_ligne)/2);
		else $left_pos = 0;
		
		
		if ($fontps) {
			$line = trim($line);
			imagepstext ($image, "$line", $fontps, $textSizePs, $black, $grey2, $left + $left_pos, $top + $lineHeight * $i, 0, 0, 0, 16);
		}
		else imagefttext($image, $textSize, 0, $left + $left_pos, $top + $lineHeight * $i, $black, $font, trim($line), array());
	}
	$retour["height"] = $height;# + round(0.3 * $hauteur_ligne);
	$retour["width"] = $largeur_max;
                 
	return $retour;
}
//array imagefttext ( resource image, float size, float angle, int x, int y, int col, string font_file, string text [, array extrainfo] )
//array imagettftext ( resource image, float size, float angle, int x, int y, int color, string fontfile, string text )

// http://doc.spip.org/@produire_image_typo
function produire_image_typo() {
	/*
	arguments autorises:
	
	$texte : le texte a transformer; attention: c'est toujours le premier argument, et c'est automatique dans les filtres
	$couleur : la couleur du texte dans l'image - pas de dieze
	$police: nom du fichier de la police (inclure terminaison)
	$largeur: la largeur maximale de l'image ; attention, l'image retournee a une largeur inferieure, selon les limites reelles du texte
	$hauteur_ligne: la hauteur de chaque ligne de texte si texte sur plusieurs lignes
	(equivalent a "line-height")
	$padding: forcer de l'espace autour du placement du texte; necessaire pour polices a la con qui "depassent" beaucoup de leur boite 
	$align: alignement left, right, center
	*/



	// Recuperer les differents arguments
	$numargs = func_num_args();
	$arg_list = func_get_args();
	$texte = $arg_list[0];
	for ($i = 1; $i < $numargs; $i++) {
		if (($p = strpos($arg_list[$i], "="))!==FALSE) {
			$nom_variable = substr($arg_list[$i], 0, $p);
			$val_variable = substr($arg_list[$i], $p+1);
		
			$variable["$nom_variable"] = $val_variable;
		}
		
	}

	// Construire requete et nom fichier
	$text = str_replace("&nbsp;", "~", $texte);	
	$text = preg_replace(",(\r|\n)+,ms", " ", $text);
	include_spip('inc/charsets');
	$text = html2unicode(strip_tags($text));
	if (strlen($text) == 0) return "";

	$taille = $variable["taille"];
	if ($taille < 1) $taille = 16;

	$couleur = couleur_html_to_hex($variable["couleur"]);
	if (strlen($couleur) < 6) $couleur = "000000";

	$alt = $texte;
		
	$align = $variable["align"];
	if (!$variable["align"]) $align="left";
	 
	$police = $variable["police"];
	if (strlen($police) < 2) $police = "dustismo.ttf";

	$largeur = $variable["largeur"];
	if ($largeur < 5) $largeur = 600;

	if ($variable["hauteur_ligne"] > 0) $hauteur_ligne = $variable["hauteur_ligne"];
	else $hauteur_ligne = 0;
	if ($variable["padding"] > 0) $padding = $variable["padding"];
	else $padding = 0;
	


	$string = "$text-$taille-$couleur-$align-$police-$largeur-$hauteur_ligne-$padding";
	$query = md5($string);
	$dossier = sous_repertoire(_DIR_VAR, 'cache-texte');
	$fichier = "$dossier$query.png";

	$flag_gd_typo = function_exists("imageftbbox")
		&& function_exists('imageCreateTrueColor');

	
	if (file_exists($fichier))
		$image = $fichier;
	else if (!$flag_gd_typo)
		return $texte;
	else {
		$font = find_in_path('polices/'.$police);
		if (!$font) {
			spip_log(_T('fichier_introuvable', array('fichier' => $police)));
			$font = find_in_path('polices/'."dustismo.ttf");
		}

		$imgbidon = imageCreateTrueColor($largeur, 45);
		$retour = printWordWrapped($imgbidon, $taille+5, 0, $largeur, $font, $couleur, $text, $taille, 'left', $hauteur_ligne);
		$hauteur = $retour["height"];
		$largeur_reelle = $retour["width"];
		$espace = $retour["espace"];
		imagedestroy($imgbidon);

		$im = imageCreateTrueColor($largeur_reelle-$espace+(2*$padding), $hauteur+5+(2*$padding));
		imagealphablending ($im, FALSE );
		imagesavealpha ( $im, TRUE );
		
		// Creation de quelques couleurs
		
		$grey2 = imagecolorallocatealpha($im, hexdec("0x{".substr($couleur, 0,2)."}"), hexdec("0x{".substr($couleur, 2,2)."}"), hexdec("0x{".substr($couleur, 4,2)."}"), 127);
		ImageFilledRectangle ($im,0,0,$largeur_reelle+(2*$padding),$hauteur+5+(2*$padding),$grey2);
		
		// Le texte a dessiner
		printWordWrapped($im, $taille+5+$padding, $padding, $largeur, $font, $couleur, $text, $taille, $align, $hauteur_ligne);
		
		
		// Utiliser imagepng() donnera un texte plus claire,
		// compare a l'utilisation de la fonction imagejpeg()
		imagepng($im, $fichier);
		imagedestroy($im);
		
		$image = $fichier;
	}


	$dimensions = getimagesize($image);
	$largeur = $dimensions[0];
	$hauteur = $dimensions[1];
	return inserer_attribut("<img src='$image' width='$largeur' height='$hauteur' style='width:".$largeur."px;height:".$hauteur."px;' />", 'alt', $alt);
}



//
// Produire des fichiers au format .ico
// avec du code recupere de :
//
//////////////////////////////////////////////////////////////
///  phpThumb() by James Heinrich <info@silisoftware.com>   //
//        available at http://phpthumb.sourceforge.net     ///
//////////////////////////////////////////////////////////////
class phpthumb_functions {
// http://doc.spip.org/@GetPixelColor
	function GetPixelColor(&$img, $x, $y) {
		if (!is_resource($img)) {
			return false;
		}
		return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
	}
// http://doc.spip.org/@LittleEndian2String
	function LittleEndian2String($number, $minbytes=1) {
		$intstring = '';
		while ($number > 0) {
			$intstring = $intstring.chr($number & 255);
			$number >>= 8;
		}
		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
	}
// http://doc.spip.org/@GD2ICOstring
	function GD2ICOstring(&$gd_image_array) {
		foreach ($gd_image_array as $key => $gd_image) {

			$ImageWidths[$key]  = ImageSX($gd_image);
			$ImageHeights[$key] = ImageSY($gd_image);
			$bpp[$key]		  = ImageIsTrueColor($gd_image) ? 32 : 24;
			$totalcolors[$key]  = ImageColorsTotal($gd_image);

			$icXOR[$key] = '';
			for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
				for ($x = 0; $x < $ImageWidths[$key]; $x++) {
					$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
					$a = round(255 * ((127 - $argb['alpha']) / 127));
					$r = $argb['red'];
					$g = $argb['green'];
					$b = $argb['blue'];

					if ($bpp[$key] == 32) {
						$icXOR[$key] .= chr($b).chr($g).chr($r).chr($a);
					} elseif ($bpp[$key] == 24) {
						$icXOR[$key] .= chr($b).chr($g).chr($r);
					}

					if ($a < 128) {
						@$icANDmask[$key][$y] .= '1';
					} else {
						@$icANDmask[$key][$y] .= '0';
					}
				}
				// mask bits are 32-bit aligned per scanline
				while (strlen($icANDmask[$key][$y]) % 32) {
					$icANDmask[$key][$y] .= '0';
				}
			}
			$icAND[$key] = '';
			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
					$icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
				}
			}

		}

		foreach ($gd_image_array as $key => $gd_image) {
			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);

			// BITMAPINFOHEADER - 40 bytes
			$BitmapInfoHeader[$key]  = '';
			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";							  // DWORD  biSize;
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);	  // LONG   biWidth;
			// The biHeight member specifies the combined
			// height of the XOR and AND masks.
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
			$BitmapInfoHeader[$key] .= "\x01\x00";									  // WORD   biPlanes;
			   $BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00";						  // wBitCount;
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";							  // DWORD  biCompression;
			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);			// DWORD  biSizeImage;
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";							  // LONG   biXPelsPerMeter;
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";							  // LONG   biYPelsPerMeter;
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";							  // DWORD  biClrUsed;
			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";							  // DWORD  biClrImportant;
		}


		$icondata  = "\x00\x00";									  // idReserved;   // Reserved (must be 0)
		$icondata .= "\x01\x00";									  // idType;	   // Resource Type (1 for icons)
		$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2);  // idCount;	  // How many images?

		$dwImageOffset = 6 + (count($gd_image_array) * 16);
		foreach ($gd_image_array as $key => $gd_image) {
			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)

			$icondata .= chr($ImageWidths[$key]);					 // bWidth;		  // Width, in pixels, of the image
			$icondata .= chr($ImageHeights[$key]);					// bHeight;		 // Height, in pixels, of the image
			$icondata .= chr($totalcolors[$key]);					 // bColorCount;	 // Number of colors in image (0 if >=8bpp)
			$icondata .= "\x00";									  // bReserved;	   // Reserved ( must be 0)

			$icondata .= "\x01\x00";								  // wPlanes;		 // Color Planes
			$icondata .= chr($bpp[$key])."\x00";					  // wBitCount;	   // Bits per pixel

			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
			$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, 4);	   // dwBytesInRes;	// How many bytes in this resource?

			$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4);	  // dwImageOffset;   // Where in the file is this image?
			$dwImageOffset += strlen($BitmapInfoHeader[$key]);
			$dwImageOffset += strlen($icXOR[$key]);
			$dwImageOffset += strlen($icAND[$key]);
		}

		foreach ($gd_image_array as $key => $gd_image) {
			$icondata .= $BitmapInfoHeader[$key];
			$icondata .= $icXOR[$key];
			$icondata .= $icAND[$key];
		}

		return $icondata;
	}

}

?>