Server : Apache System : Linux webd348.cluster026.gra.hosting.ovh.net 5.15.148-ovh-vps-grsec-zfs-classid #1 SMP Thu Feb 8 09:41:04 UTC 2024 x86_64 User : hednacluml ( 122243) PHP Version : 8.3.9 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl Directory : /home/hednacluml/info/plugins-dist/filtres_images/filtres/ |
<?php /***************************************************************************\ * SPIP, Système de publication pour l'internet * * * * Copyright © avec tendresse depuis 2001 * * Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ /** * Toutes les fonctions image_xx de ce fichier : * - prennent une image en entree * - fournissent une image en sortie * - sont chainables les unes derrieres les autres dans toutes les combinaisons possibles * * @package SPIP\FiltresImages\ImagesTransforme */ if (!defined('_ECRIRE_INC_VERSION')) { return; } // librairie de base du core include_spip('inc/filtres_images_mini'); // 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) // 3/ $transparence a "true" permet de conserver la transparence (utile pour conversion GIF) function image_aplatir($im, $format = 'jpg', $coul = '000000', $qualite = null, $transparence = false) { $transp_y = null; if ($qualite === null) { if (in_array($format, ['jpg', 'webp'])) { $qualite = _IMG_GD_QUALITE; } elseif ($format == 'png') { $qualite = 0; } else { $qualite = 128; } } $fonction = ['image_aplatir', func_get_args()]; $image = _image_valeurs_trans($im, "aplatir-$format-$coul-$qualite-$transparence", $format, $fonction, '', _SVG_SUPPORTED); if (!$image) { return (''); } if ($image['format_source'] === 'svg') { // ne pas forcer le format $image = _image_valeurs_trans($im, "aplatir-$format-$coul-$qualite-$transparence", false, $fonction, '', _SVG_SUPPORTED); } 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) { if ($image['format_source'] === 'svg') { if ($transparence) { $svg = svg_charger($im); } else { $svg = svg_ajouter_background($im, $coul); } _image_gd_output($svg, $image); } else { $im = @$image['fonction_imagecreatefrom']($im); if (!$im) { return ''; } 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); $transp_x = false; if ($image['format_source'] == 'jpg') { imagedestroy($im_); $im_ = $im; } else { $has_transparent = false; 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; if ($a > 0) { $has_transparent = true; // transparence complete if ($a == 127) { $r = $dr; $g = $dv; $b = $db; $transp_x = $x; // Memoriser un point transparent $transp_y = $y; } else { $p = (127 - $a) / 127; $r = round($p * $r + $dr * (1 - $p)); $g = round($p * $g + $dv * (1 - $p)); $b = round($p * $b + $db * (1 - $p)); } if ($transparence) { $color = ImageColorAllocateAlpha($im_, $r, $g, $b, $a); } else { $color = ImageColorAllocate($im_, $r, $g, $b); } imagesetpixel($im_, $x, $y, $color); } } } // si on avait aucun pixel transparent, reprendre l'image d'origine telle quelle if (!$has_transparent) { imagedestroy($im_); $im_ = $im; } } // 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 si possible, sinon on en recree une) $im = imagecreatetruecolor($x_i, $y_i); // copier l'image true color imagecopy($im, $im_, 0, 0, 0, 0, $x_i, $y_i); // et la transformer en palette @imagetruecolortopalette($im, true, $qualite); // 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); } if ($im !== $im_) { imagedestroy($im); } imagedestroy($im_); } } return _image_ecrire_tag($image, ['src' => $dest]); } // Enregistrer une image dans un format donne // (conserve la transparence gif, png, ico) // utilise [->@image_aplatir] function image_format($img, $format = 'png') { $qualite = null; if ($format == 'png8') { $format = 'png'; $qualite = 128; } return image_aplatir($img, $format, 'cccccc', $qualite, true); } // Transforme l'image en PNG transparent // alpha = 0: aucune transparence // alpha = 127: completement transparent function image_alpha($im, $alpha = 63) { $fonction = ['image_alpha', func_get_args()]; $image = _image_valeurs_trans($im, "alpha-$alpha", 'png', $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } if ($image['format_source'] === 'svg') { // ne pas forcer le format $image = _image_valeurs_trans($im, "alpha-$alpha", false, $fonction, '', _SVG_SUPPORTED); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { $atts = []; if ($alpha > 0) { $atts['opacity'] = round((127 - $alpha) / 127.0, 2); } $svg = svg_transformer($im, $atts); _image_gd_output($svg, $image); } else { // 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, ['src' => $dest]); } /** * Recadre (rogne) une image en indiquant la taille de la découpe souhaitée * * On peut indiquer une proportion ou une taille spécifique, une position de rognage * et une couleur de fond, si le rognage est de taille plus grande que l'image d'origine. * * @example * - `[(#FICHIER|image_recadre{800, 400})]` * - `[(#FICHIER|image_recadre{800, 400, center})]` * - `[(#FICHIER|image_recadre{800, 400, center, black})]` * - `[(#FICHIER|image_recadre{16:9})]` * - `[(#FICHIER|image_recadre{16:9, -})]` (- est appliqué par défaut, équivalent à image_passe_partout) * - `[(#FICHIER|image_recadre{16:9, +, center, white})]` * - `[(#FICHIER|image_recadre{16:9, -, top left})]` * - `[(#FICHIER|image_recadre{16:9, -, top=40 left=20})]` * * @filtre * @uses _image_valeurs_trans() * @uses _image_tag_changer_taille() si image trop grande pour être traitée * @uses _image_ecrire_tag() * @link https://www.spip.net/5786 * * @param string $im * Chemin de l'image ou balise html `<img src=... />` * @param string|int $width * Largeur du recadrage * ou ratio sous la forme "16:9" * @param string|int $height * Hauteur du recadrage * ou "+" (agrandir) ou "-" (reduire) si un ratio est fourni pour width * @param string $position * Indication de position de la découpe : * - `center`, `left`, `right`, `top`, `bottom`, * - ou combinaisons de plusiers `top left` * - ou indication en pixels depuis une position `top=50` ou composée `top=40 left=50` * - ou nom d'une fonction spéciale qui calculera et retournera la position souhaitée * @param string $background_color * Couleur de fond si on agrandit l'image * @return string * balise image recadrée */ function image_recadre($im, $width, $height = '-', $position = 'center', $background_color = 'white') { $fonction = ['image_recadre', func_get_args()]; $forcer_format = false; $background_color = strtolower(trim($background_color)); $position = strtolower(trim($position)); $image = _image_valeurs_trans($im, "recadre-$width-$height-$position-$background_color", $forcer_format, $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; // on recadre pour respecter un ratio ? // width : "16:9" // height : "+" pour agrandir l'image et "-" pour la croper if (strpos($width, ':') !== false) { [$wr, $hr] = explode(':', $width); $hm = $x_i / $wr * $hr; $ym = $y_i / $hr * $wr; if ($height == '+' ? ($y_i < $hm) : ($y_i > $hm)) { $width = $x_i; $height = round($hm); } else { $width = round($ym); $height = $y_i; } } if ($image['format_source'] !== 'svg' && _IMG_GD_MAX_PIXELS && $x_i * $y_i > _IMG_GD_MAX_PIXELS) { spip_log("image_recadre impossible sur $im : " . $x_i * $y_i . 'pixels'); // on se rabat sur une reduction CSS return _image_tag_changer_taille($im, $width, $height); } if ($width == 0) { $width = $x_i; } if ($height == 0) { $height = $y_i; } $offset_width = $x_i - $width; $offset_height = $y_i - $height; if ($background_color === 'transparent') { if ($width > $x_i or $height > $y_i) { if ($image['format_source'] !== 'svg') { $forcer_format = 'png'; } $image = _image_valeurs_trans($im, "recadre-$width-$height-$position-$background_color", $forcer_format, $fonction, false, _SVG_SUPPORTED); } } // chercher une fonction spéciale de calcul des coordonnées de positionnement. // exemple 'focus' ou 'focus-center' avec le plugin 'Centre Image' if (!in_array($position, ['center', 'top', 'right', 'bottom', 'left'])) { if (count(explode(' ', $position)) == 1) { $positionner = charger_fonction('image_positionner_par_' . str_replace('-', '_', $position), 'inc', true); if ($positionner) { $position = $positionner($im, $width, $height); } } } 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) { if ($image['format_source'] === 'svg') { $svg = svg_recadrer($im, $width, $height, $offset_width, $offset_height, $background_color); _image_gd_output($svg, $image); } else { $im = $image['fonction_imagecreatefrom']($im); if (!$im) { return ''; } 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, ['src' => $dest, 'width' => $width, 'height' => $height]); } /** * Recadrer une image dans le rectangle le plus petit possible sans perte * de pixels non transparent * Le recadrage se fait en conservant le centre de l'image : on recadre symétriquement gauche vs droite et haut vs bas * TODO : proposer une option pour vraiment recadrer au plus juste, meme si ca decentre l'image * * @param string $im * @return string */ function image_recadre_mini($im) { $fonction = ['image_recadre_mini', func_get_args()]; $image = _image_valeurs_trans($im, 'recadre_mini', false, $fonction); if (!$image) { return (''); } $width = $image['largeur']; $height = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { $im = $image['fonction_imagecreatefrom']($im); imagepalettetotruecolor($im); // trouver le rectangle mini qui contient des infos de couleur // recherche optimisee qui ne balaye que par zone $min_x = $width; $min_y = $height; $max_y = $max_x = 0; $yy = 0; while ($yy <= $height / 2 and $max_y <= $min_y) { if ($yy < $min_y) { for ($xx = 0; $xx < $width; $xx++) { $color_index = imagecolorat($im, $xx, $yy); $color_tran = imagecolorsforindex($im, $color_index); if ($color_tran['alpha'] !== 127) { $min_y = min($yy, $min_y); $max_y = max($height - 1 - $yy, $max_y); break; } } } if ($height - 1 - $yy > $max_y) { for ($xx = 0; $xx < $width; $xx++) { $color_index = imagecolorat($im, $xx, $height - 1 - $yy); $color_tran = imagecolorsforindex($im, $color_index); if ($color_tran['alpha'] !== 127) { $min_y = min($yy, $min_y); $max_y = max($height - 1 - $yy, $max_y); break; } } } $yy++; } $min_y = min($max_y, $min_y); // tout a 0 aucun pixel trouve $xx = 0; while ($xx <= $width / 2 and $max_x <= $min_x) { if ($xx < $min_x) { for ($yy = $min_y; $yy < $max_y; $yy++) { $color_index = imagecolorat($im, $xx, $yy); $color_tran = imagecolorsforindex($im, $color_index); if ($color_tran['alpha'] !== 127) { $min_x = min($xx, $min_x); $max_x = max($xx, $max_x); break; // inutile de continuer sur cette colonne } } } if ($width - 1 - $xx > $max_x) { for ($yy = $min_y; $yy < $max_y; $yy++) { $color_index = imagecolorat($im, $width - 1 - $xx, $yy); $color_tran = imagecolorsforindex($im, $color_index); if ($color_tran['alpha'] !== 127) { $min_x = min($width - 1 - $xx, $min_x); $max_x = max($width - 1 - $xx, $max_x); break; // inutile de continuer sur cette colonne } } } $xx++; } $min_x = min($max_x, $min_x); // tout a 0 aucun pixel trouve $width = $max_x - $min_x + 1; $height = $max_y - $min_y + 1; $im_ = imagecreatetruecolor($width, $height); @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, $min_x, $min_y, $width, $height); _image_gd_output($im_, $image); imagedestroy($im_); imagedestroy($im); } else { [$height, $width] = taille_image($image['fichier_dest']); } return _image_ecrire_tag($image, ['src' => $dest, 'width' => $width, 'height' => $height]); } function image_flip_vertical($im) { $fonction = ['image_flip_vertical', func_get_args()]; $image = _image_valeurs_trans($im, 'flip_v', false, $fonction, '', _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { $svg = svg_flip($im, 'v'); _image_gd_output($svg, $image); } else { $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, ['src' => $dest]); } function image_flip_horizontal($im) { $fonction = ['image_flip_horizontal', func_get_args()]; $image = _image_valeurs_trans($im, 'flip_h', false, $fonction, '', _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { $svg = svg_flip($im, 'h'); _image_gd_output($svg, $image); } else { $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, ['src' => $dest]); } function image_masque($im, $masque, $pos = '') { $defini = []; $rgb3 = []; // 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 = []; $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 = ['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 (['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, ['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, ['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_, intval($r_), intval($g_), intval($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, ['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" function image_nb($im, $val_r = 299, $val_g = 587, $val_b = 114) { $fonction = ['image_nb', func_get_args()]; $image = _image_valeurs_trans($im, "nb-$val_r-$val_g-$val_b", false, $fonction, false, _SVG_SUPPORTED); 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) { if ($image['format_source'] === 'svg') { #$svg = svg_transformer($im, ['style' => "filter:grayscale(100%);"]); // ne semble pas fonctionner dans Safari+Chrome $svg = svg_filter_grayscale($im, 1.0); _image_gd_output($svg, $image); } else { // 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, ['src' => $dest]); } 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 = [ [1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1], [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1], [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1] ]; $fonction = ['image_flou', func_get_args()]; $image = _image_valeurs_trans($im, "flou-$niveau", false, $fonction, '', _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $sum = 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! $new_width = $x_i + $niveau; $new_height = $y_i + $niveau; if ($creer) { spip_timer('image_flou'); if ($image['format_source'] === 'svg') { spip_log($log = "image_flou: $im via SVG", 'images' . _LOG_DEBUG); $svg = svg_recadrer($im, $new_width, $new_height, round(($x_i - $new_width) / 2), round(($y_i - $new_height) / 2)); #$svg = svg_transformer($svg, ['style' => "filter:blur({$niveau}px);"]); // ne semble pas supporte par safari+chrome $svg = svg_filter_blur($svg, $niveau); _image_gd_output($svg, $image); } else { spip_log($log = "image_flou: $im via gd legacy", 'images' . _LOG_DEBUG); // Creation de l'image en deux temps // de facon a conserver les GIF transparents $im = $image['fonction_imagecreatefrom']($im); imagepalettetotruecolor($im); if ($niveau > 0) { $temp1 = imagecreatetruecolor($new_width, $y_i); $temp2 = imagecreatetruecolor($new_width, $new_height); @imagealphablending($temp1, false); @imagesavealpha($temp1, true); @imagealphablending($temp2, false); @imagesavealpha($temp2, true); for ($i = 0; $i < $new_width; $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) { $idelta = ($i - $niveau) + $k; if ($idelta < 0 || $idelta >= $x_i) { $a = 127; $r = $g = $b = 255; } else { $color = imagecolorat($im, $idelta, $j); $a = ($color >> 24) & 0xFF; $r = ($color >> 16) & 0xFF; $g = ($color >> 8) & 0xFF; $b = ($color) & 0xFF; } $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, round($sumr / $sum), round($sumg / $sum), round($sumb / $sum), round($suma / $sum_)); } else { $color = ImageColorAllocateAlpha($temp1, 255, 255, 255, 127); } imagesetpixel($temp1, $i, $j, $color); } } imagedestroy($im); for ($i = 0; $i < $new_width; $i++) { for ($j = 0; $j < $new_height; $j++) { $suma = 0; $sumr = 0; $sumg = 0; $sumb = 0; $sum = 0; $sum_ = 0; for ($k = 0; $k <= $niveau; ++$k) { $jdelta = $j - $niveau + $k; if ($jdelta < 0 || $jdelta >= $y_i) { $a = 127; $r = $g = $b = 255; } else { $color = imagecolorat($temp1, $i, $jdelta); $a = ($color >> 24) & 0xFF; $r = ($color >> 16) & 0xFF; $g = ($color >> 8) & 0xFF; $b = ($color) & 0xFF; } $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, round($sumr / $sum), round($sumg / $sum), round($sumb / $sum), round($suma / $sum_)); } else { $color = ImageColorAllocateAlpha($temp2, 255, 255, 255, 127); } imagesetpixel($temp2, $i, $j, $color); } } _image_gd_output($temp2, $image); imagedestroy($temp1); imagedestroy($temp2); } else { _image_gd_output($im, $image); imagedestroy($im); } } spip_log($log . " en " . spip_timer('image_flou'), 'images' . _LOG_DEBUG); } return _image_ecrire_tag($image, ['src' => $dest, 'width' => $new_width, 'height' => $new_height]); } /** * Determiner les nouvelles dimensions de l'image apres rotation * @param int|float $angle * en degres * @param int $width * @param int $height * @param int $center_x * @param int $center_y * @return array * [int, int] */ function dimensions_rotation_image($angle, $width, $height, $center_x = null, $center_y = null) { 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); if (is_null($center_x)) { $center_x = floor(($width - 1) / 2); } if (is_null($center_y)) { $center_y = floor(($height - 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 = [[0, 0], [$width, 0], [$width, $height], [0, $height]]; foreach ($corners as $key => $value) { $value[0] -= $center_x; //Translate coords to center for rotation $value[1] -= $center_y; $temp = []; $temp[0] = $value[0] * $cosangle + $value[1] * $sinangle; $temp[1] = $value[1] * $cosangle - $value[0] * $sinangle; $corners[$key] = $temp; } $min_x = 1_000_000_000_000_000; $max_x = -1_000_000_000_000_000; $min_y = 1_000_000_000_000_000; $max_y = -1_000_000_000_000_000; 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 = $height; $rotate_width = $width; } else { $rotate_height = $width; $rotate_width = $height; } } return [$rotate_width, $rotate_height, $droit]; } function image_RotateBicubic($src_img, $angle, $bicubic = false) { include_spip('filtres/images_lib'); $src_x = imagesx($src_img); $src_y = imagesy($src_img); $center_x = floor(($src_x - 1) / 2); $center_y = floor(($src_y - 1) / 2); [$rotate_width, $rotate_height, $droit] = dimensions_rotation_image($angle, $src_x, $src_y, $center_x, $center_y); $rotate = imagecreatetruecolor($rotate_width, $rotate_height); imagealphablending($rotate, false); imagesavealpha($rotate, true); // convert degrees to radians $angle = $angle + 180; $angle = deg2rad($angle); $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); $bicubic = false; } $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... function image_rotation($im, $angle, $crop = false) { $fonction = ['image_rotation', func_get_args()]; $image = _image_valeurs_trans($im, "rot-$angle-$crop", 'png', $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } if ($image['format_source'] === 'svg') { // ne pas forcer le format $image = _image_valeurs_trans($im, "rot-$angle-$crop", false, $fonction, false, _SVG_SUPPORTED); } $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { $center_x = floor(($image['largeur'] - 1) / 2); $center_y = floor(($image['hauteur'] - 1) / 2); [$rotate_width, $rotate_height, $droit] = dimensions_rotation_image($angle, $image['largeur'], $image['hauteur'], $center_x, $center_y); $svg = svg_recadrer($im, $rotate_width, $rotate_height, -round(($rotate_width - $image['largeur']) / 2), -round(($rotate_height - $image['hauteur']) / 2)); $svg = svg_rotate($svg, $angle, 0.5, 0.5); _image_gd_output($svg, $image); } else { $effectuer_gd = true; if (method_exists(\Imagick::class, 'rotateImage')) { $imagick = new Imagick(); $imagick->readImage($im); $imagick->rotateImage(new ImagickPixel('none'), $angle); $imagick->writeImage($dest); $effectuer_gd = false; } else { if ($GLOBALS['meta']['image_process'] == 'convert') { if (_CONVERT_COMMAND != '') { @define('_CONVERT_COMMAND', 'convert'); @define('_ROTATE_COMMAND', _CONVERT_COMMAND . ' -background none -rotate %t %src %dest'); } else { @define('_ROTATE_COMMAND', ''); } if (_ROTATE_COMMAND !== '') { $commande = str_replace( ['%t', '%src', '%dest'], [ $angle, escapeshellcmd($im), escapeshellcmd($dest) ], _ROTATE_COMMAND ); spip_log($commande); exec($commande); if (file_exists($dest)) { // precaution $effectuer_gd = false; } } } // cette variante genere-t-elle un fond transparent // dans les coins vide issus de la rotation ? elseif (function_exists('imagick_rotate')) { $handle = imagick_readimage($im); if ($handle && imagick_isopaqueimage($handle)) { imagick_setfillcolor($handle, 'transparent'); imagick_rotate($handle, $angle); imagick_writeimage($handle, $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); } } } [$src_y, $src_x] = taille_image($dest); return _image_ecrire_tag($image, ['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/ function image_imagick() { $arr = []; $tous = func_get_args(); $img = $tous[0]; $fonc = $tous[1]; $tous[0] = ''; $tous_var = join($tous, '-'); $fonction = ['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 (method_exists(\Imagick::class, $fonc)) { $imagick = new Imagick(); $imagick->readImage($im); $args = $tous; array_shift($args); array_shift($args); call_user_func_array([$imagick, $fonc], $args); _image_gd_output($imagick, $image, _IMG_GD_QUALITE, '_image_imagick_write'); } elseif (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); _image_gd_output($handle, $image, _IMG_GD_QUALITE, '_image_imagick_write'); } } [$src_y, $src_x] = taille_image($dest); return _image_ecrire_tag($image, ['src' => $dest, 'width' => $src_x, 'height' => $src_y]); } /** * Affiche ou sauvegarde une image au format WEBP * * Utilise les fonctions spécifiques GD. * * @param resource $img * Une ressource de type Imagick ou handle * @param string $fichier * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png). * @return bool * * - false si l'image créée a une largeur nulle ou n'existe pas ; * - true si une image est bien retournée. */ function _image_imagick_write($imagick, $fichier, $qualite = _IMG_GD_QUALITE) { $tmp = $fichier . '.tmp'; if (is_a($imagick, 'Imagick')) { $ret = $imagick->writeImage($tmp); } else { $ret = imagick_writeimage($imagick, $tmp); } if (file_exists($tmp)) { $taille_test = getimagesize($tmp); if ($taille_test[0] < 1) { return false; } spip_unlink($fichier); // le fichier peut deja exister @rename($tmp, $fichier); return $ret; } return false; } // Permet de rendre une image // plus claire (gamma > 0) // ou plus foncee (gamma < 0) function image_gamma($im, $gamma = 0) { include_spip('filtres/images_lib'); $fonction = ['image_gamma', func_get_args()]; $image = _image_valeurs_trans($im, "gamma-$gamma", false, $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { $pc = round($gamma / 255, 2); if ($pc > 0) { $svg = svg_ajouter_voile($im, '#ffffff', $pc); } else { $svg = svg_ajouter_voile($im, '#000000', -$pc); } _image_gd_output($svg, $image); } else { // 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_decale_composante($r, $gamma); $g = _image_decale_composante($g, $gamma); $b = _image_decale_composante($b, $gamma); $color = ImageColorAllocateAlpha($im_, $r, $g, $b, $a); imagesetpixel($im_, $x, $y, $color); } } _image_gd_output($im_, $image); } } return _image_ecrire_tag($image, ['src' => $dest]); } // Passe l'image en "sepia" // On peut fixer les valeurs RGB // de la couleur "complementaire" pour forcer une dominante //function image_sepia($im, $dr = 137, $dv = 111, $db = 94) function image_sepia($im, $rgb = '896f5e') { include_spip('filtres/images_lib'); if (!function_exists('imagecreatetruecolor')) { return $im; } $couleurs = _couleur_hex_to_dec($rgb); $dr = $couleurs['red']; $dv = $couleurs['green']; $db = $couleurs['blue']; $fonction = ['image_sepia', func_get_args()]; $image = _image_valeurs_trans($im, "sepia-$dr-$dv-$db", false, $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { if ($image['format_source'] === 'svg') { #$svg = svg_transformer($im, ['style' => "filter:sepia(1);"]); // ne fonctionne pas dans Chrome+Safari $svg = svg_filter_sepia($im, 1); _image_gd_output($svg, $image); } else { // 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_decale_composante_127($r, $dr); $g = _image_decale_composante_127($g, $dv); $b = _image_decale_composante_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, ['src' => $dest]); } /** * Renforcer la netteté d'une image * * @param string $im * Code HTML de l'image * @param float $k * Niveau de renforcement (entre 0 et 1) * @return string Code HTML de l'image **/ function image_renforcement($im, $k = 0.5) { $rgb = []; $fonction = ['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[1][1] >> 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, intval($r))); $g = min(255, max(0, intval($g))); $b = min(255, max(0, intval($b))); $color = ImageColorAllocateAlpha($im_, $r, $g, $b, $a); imagesetpixel($im_, $x, $y, $color); } } _image_gd_output($im_, $image); } return _image_ecrire_tag($image, ['src' => $dest]); } /** * Transforme la couleur de fond de l'image en transparence * Le filtre ne gere pas la notion de contiguite aux bords, et affectera tous les pixels de l'image dans la couleur visee * $background_color : couleur cible * $tolerance : distance L1 dans l'espace RGB des couleur autour de la couleur $background_color pour lequel la transparence sera appliquee * $alpha : transparence a appliquer pour les pixels de la couleur cibles avec la tolerance ci-dessus * $coeff_lissage : coeff applique a la tolerance pour determiner la decroissance de la transparence fonction de la distance L1 entre la couleur du pixel et la couleur cible * * @param string $im * @param string $background_color * @param int $tolerance * @param int $alpha * alpha = 0: aucune transparence * alpha = 127: completement transparent * @param int $coeff_lissage * @return mixed|null|string */ function image_fond_transparent($im, $background_color, $tolerance = 12, $alpha = 127, $coeff_lissage = 7) { $fonction = ['image_fond_transparent', func_get_args()]; $image = _image_valeurs_trans($im, "fond_transparent-$background_color-$tolerance-$coeff_lissage-$alpha", 'png', $fonction, false, _SVG_SUPPORTED); if (!$image) { return (''); } if ($image['format_source'] === 'svg') { // Ne rien faire si SVG $image = _image_valeurs_trans($im, "fond_transparent-$background_color-$tolerance-$coeff_lissage-$alpha", false, $fonction); } $x_i = $image['largeur']; $y_i = $image['hauteur']; $im = $image['fichier']; $dest = $image['fichier_dest']; $creer = $image['creer']; if ($creer) { $bg = _couleur_hex_to_dec($background_color); $bg_r = $bg['red']; $bg_g = $bg['green']; $bg_b = $bg['blue']; // 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); $color_f = ImageColorAllocateAlpha($im_, 255, 255, 255, $alpha); for ($x = 0; $x < $x_i; $x++) { for ($y = 0; $y < $y_i; $y++) { $rgb = ImageColorAt($im2, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; if ((($d = abs($r - $bg_r) + abs($g - $bg_g) + abs($b - $bg_b)) <= $tolerance)) { imagesetpixel($im_, $x, $y, $color_f); } elseif ($tolerance and $d <= ($coeff_lissage + 1) * $tolerance) { $transp = round($alpha * (1 - ($d - $tolerance) / ($coeff_lissage * $tolerance))); $color_p = ImageColorAllocateAlpha($im_, $r, $g, $b, $transp); imagesetpixel($im_, $x, $y, $color_p); } else { imagesetpixel($im_, $x, $y, $rgb); } } } _image_gd_output($im_, $image); imagedestroy($im_); imagedestroy($im); imagedestroy($im2); } return _image_ecrire_tag($image, ['src' => $dest]); }