function couleur_hsv2rgb($H, $S, $V) { include_spip('filtres/images_lib'); return _couleur_hsv2rgb($H, $S, $V); }
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 masque 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, ecran, superposer, lumiere_dure, teinte, saturation, valeur // https://en.wikipedia.org/wiki/Blend_modes // 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 // ecran: effet inverse de 'produit' -> l'image resultante est plus claire // superposer: combine les modes 'produit' et 'ecran' -> les parties claires sont eclaircies, les parties sombres assombries. // lumiere_dure: equivalent a 'superposer', sauf que l'image du bas et du haut sont inversees. // teinte: utilise la teinte du masque // saturation: utilise la saturation du masque // valeur: utilise la valeur du masque $mode = "masque"; $numargs = func_num_args(); $arg_list = func_get_args(); $variable = array(); $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 (isset($defini["mode"]) and $defini["mode"]) { $mode = $variable["mode"]; } // utiliser _image_valeurs_trans pour accepter comme masque : // - une balise <img src='...' /> // - une image avec un timestamp ?01234 $mask = _image_valeurs_trans($masque, "source-image_masque", "png", null, true); if (!$mask) { return ""; } $masque = $mask['fichier']; $pos = md5(serialize($variable) . $mask['date_src']); $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"]; // doit-on positionner l'image ? $placer = false; foreach (array("right", "left", "bottom", "top", "text-align", "vertical-align") as $pl) { if (isset($defini[$pl]) and $defini[$pl]) { $placer = true; break; } } if ($creer) { $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 (isset($defini["right"]) and $defini["right"]) { $right = $variable["right"]; $dx = $x_i - $x_m - $right; } if (isset($defini["bottom"]) and $defini["bottom"]) { $bottom = $variable["bottom"]; $dy = $y_i - $y_m - $bottom; } if (isset($defini["top"]) and $defini["top"]) { $top = $variable["top"]; $dy = $top; } if (isset($defini["left"]) and $defini["left"]) { $left = $variable["left"]; $dx = $left; } if (isset($defini["text-align"]) and $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 (isset($defini["vertical-align"]) and $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); // calcul couleurs de chaque pixel selon les modes de fusion for ($x = 0; $x < $x_dest; $x++) { for ($y = 0; $y < $y_dest; $y++) { $rgb = ImageColorAt($im2, $x, $y); // image au dessus $a = $rgb >> 24 & 0xff; $r = $rgb >> 16 & 0xff; $g = $rgb >> 8 & 0xff; $b = $rgb & 0xff; $rgb2 = ImageColorAt($im, $x + $x_dec, $y + $y_dec); // image en dessous $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 (in_array($mode, array("produit", "difference", "superposer", "lumiere_dure", "ecran"))) { if ($mode == "produit") { $r = $r / 255 * $r2; $g = $g / 255 * $g2; $b = $b / 255 * $b2; } elseif ($mode == "difference") { $r = abs($r - $r2); $g = abs($g - $g2); $b = abs($b - $b2); } elseif ($mode == "superposer") { $r = $r2 < 128 ? 2 * $r * $r2 / 255 : 255 - 2 * (255 - $r) * (255 - $r2) / 255; $g = $g2 < 128 ? 2 * $g * $g2 / 255 : 255 - 2 * (255 - $g) * (255 - $g2) / 255; $b = $b2 < 128 ? 2 * $b * $b2 / 255 : 255 - 2 * (255 - $b) * (255 - $b2) / 255; } elseif ($mode == "lumiere_dure") { $r = $r < 128 ? 2 * $r * $r2 / 255 : 255 - 2 * (255 - $r2) * (255 - $r) / 255; $g = $g < 128 ? 2 * $g * $g2 / 255 : 255 - 2 * (255 - $g2) * (255 - $g) / 255; $b = $b < 128 ? 2 * $b * $b2 / 255 : 255 - 2 * (255 - $b2) * (255 - $b) / 255; } elseif ($mode == "ecran") { $r = 255 - (255 - $r) * (255 - $r2) / 255; $g = 255 - (255 - $g) * (255 - $g2) / 255; $b = 255 - (255 - $b) * (255 - $b2) / 255; } $r = max(0, min($r, 255)); $g = max(0, min($g, 255)); $b = max(0, min($b, 255)); // melange en fonction de la transparence du masque $v = (127 - $a) / 127; if ($v == 1) { // melange complet $r_ = $r; $g_ = $g; $b_ = $b; } else { $v2 = (127 - $a2) / 127; if ($v + $v2 == 0) { // ?? $r_ = $r2; $g_ = $g2; $b_ = $b2; } else { // pas de melange (transparence du masque) $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); } elseif (in_array($mode, array("teinte", "saturation", "valeur"))) { include_spip("filtres/images_lib"); $hsv = _couleur_rgb2hsv($r, $g, $b); // image au dessus $h = $hsv["h"]; $s = $hsv["s"]; $v = $hsv["v"]; $hsv2 = _couleur_rgb2hsv($r2, $g2, $b2); // image en dessous $h2 = $hsv2["h"]; $s2 = $hsv2["s"]; $v2 = $hsv2["v"]; switch ($mode) { case "teinte": $rgb3 = _couleur_hsv2rgb($h, $s2, $v2); break; case "saturation": $rgb3 = _couleur_hsv2rgb($h2, $s, $v2); break; case "valeur": $rgb3 = _couleur_hsv2rgb($h2, $s2, $v); break; } $r = $rgb3["r"]; $g = $rgb3["g"]; $b = $rgb3["b"]; // melange en fonction de la transparence du masque $v = (127 - $a) / 127; if ($v == 1) { // melange complet $r_ = $r; $g_ = $g; $b_ = $b; } else { $v2 = (127 - $a2) / 127; if ($v + $v2 == 0) { // ?? $r_ = $r2; $g_ = $g2; $b_ = $b2; } else { // pas de melange (transparence du masque) $r_ = $r + ($r2 - $r) * $v2 * (1 - $v); $g_ = $g + ($g2 - $g) * $v2 * (1 - $v); $b_ = $b + ($b2 - $b) * $v2 * (1 - $v); } } $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)); }