Contactez-nous

1

Tracer les contours de transparence

3 avril 2006
par ARNO*

[SPIP 1.9 et GD2] On a souvent besoin de faire ressortir les contours entre différentes zones à l’intérieur d’une image : il s’agit notamment de « dessiner » les frontières entre deux couleurs. Notre but est un peu plus modeste aujourd’hui : nous allons dessiner les frontières entre deux zones de niveaux de transparence.

L’utilisation principale est de pouvoir dessiner les contours d’un lettrage réalisé avec image_typo. Comme le filtre travaillera sur les différences de transparence, ces images typographiques sont particulièrement adaptées.

En revanche, le filtre ne peut pas du tout s’appliquer directement à une photographie (puisque celle-ci ne comporte aucune zone de transparence) ; il est cependant possible, en jouant avec ce nouveau filtre et notre filtre image_podpod d’obtenir des effets plutôt sympathiques :

Notre filtre se nomme image_contour_alpha :

  1. function image_contour_alpha($im, $coul='000000', $trait=1)
  2. {
  3. $image = valeurs_image_trans($im, "contour-$coul-$trait", "png");
  4. if (!$image) return("");
  5.  
  6. include_ecrire("filtres");
  7. $couleurs = couleur_hex_to_dec($coul);
  8. $dr= $couleurs["red"];
  9. $dv= $couleurs["green"];
  10. $db= $couleurs["blue"];
  11.  
  12. $x_i = $image["largeur"];
  13. $y_i = $image["hauteur"];
  14.  
  15. $im = $image["fichier"];
  16. $dest = $image["fichier_dest"];
  17.  
  18. $creer = $image["creer"];
  19.  
  20. if ($creer) {
  21. $im = $image["fonction_imagecreatefrom"]($im);
  22. $im_ = imagecreatetruecolor($x_i, $y_i);
  23. @imagealphablending($im_, false);
  24. @imagesavealpha($im_,true);
  25. $color_t = ImageColorAllocateAlpha( $im_, 255, 255, 255 , 127 );
  26. imagefill ($im_, 0, 0, $color_t);
  27.  
  28. for ($x = 0; $x < $x_i; $x++) {
  29. for ($y=0; $y < $y_i; $y++) {
  30.  
  31. $rgb = ImageColorAt($im, $x, $y);
  32. $a = ($rgb >> 24) & 0xFF;
  33.  
  34. $dif = false;
  35. $m = 0;
  36. $t = 0;
  37. for ($ix = -1*$trait/2; $ix <= $trait/2; $ix++) {
  38. for ($iy = -1*$trait/2; $iy <= $trait/2; $iy++) {
  39. $x2 = $x + $ix;
  40. $y2 = $y + $iy;
  41. if ($x2 >=0 AND $y2 >= 0 AND $x2 < $x_i AND $y2 < $y_i) {
  42. $t++;
  43. $rgb2 = ImageColorAt($im, $x2, $y2);
  44. $a2 = ($rgb2 >> 24) & 0xFF;
  45. $r2 = ($rgb2 >> 16) & 0xFF;
  46. $g2 = ($rgb2 >> 8) & 0xFF;
  47. $b2 = $rgb2 & 0xFF;
  48.  
  49. if ($a != $a2) {
  50. $dx = min(abs($ix),abs($iy));
  51. $dy = max(abs($ix),abs($iy));
  52. if ($mem[$dx][$dy]) $d = $mem[$dx][$dy];
  53. else {
  54. $mem[$dx][$dy] = sqrt(($dx)*($dx)+($dy)*($dy));
  55. $d = $mem[$dx][$dy];
  56. }
  57. if ($d>0) {
  58. $m = $m + (abs($a2-$a) / $d);
  59. } else {
  60. $m = $m + 127;
  61. }
  62. }
  63. }
  64. }
  65. }
  66. $m = 127 - (($m / $t) * $trait);
  67. $m = min(max($m, 0), 127);
  68.  
  69. $color = ImageColorAllocateAlpha( $im_, $dr, $dv, $db , round($m) );
  70. imagesetpixel ($im_, $x, $y, $color);
  71. }
  72. }
  73. $image["fonction_image"]($im_, "$dest");
  74. }
  75.  
  76. $class = $image["class"];
  77. if (strlen($class) > 1) $tags=" class='$class'";
  78. $tags = "$tags alt='".$image["alt"]."'";
  79. $style = $image["style"];
  80. if (strlen($style) > 1) $tags="$tags style='$style'";
  81.  
  82. return "<img src='$dest'$tags />";
  83. }

Télécharger

Comme toujours, la partie intéressante se trouve à l’intérieur de la double boucle qui permet de parcourir chaque pixel de l’image. Nous ne détaillerons pas le code, pour une fois, car il est un peu « bidouillesque » (ceci afin de gagner en temps de calcul, ce filtre étant particulièrement lourd).

L’idée générale :
— pour chaque pixel de l’image, on parcourt un carré autour de ce pixel, sur une « épaisseur » égale à l’épaisseur du contour souhaité ($trait) ;
— pour chacun des pixels de ce carré, on récupère la différence de transparence par rapport au pixel central, que l’on divise par la distance par rapport au centre ;
— on fait la moyenne de ces différences de transparence, et c’est (en gros) cette différence de transparence que l’on applique au pixel.

Ce qui revient à dire :
— si un pixel est entouré de pixels ayant la même transparence que lui, alors il devient transparent ;
— si un pixel est proche d’un pixel de transparence différent de lui, alors il devient visible.

De cette façon, on rend visible les pixels qui se trouvent à la « frontière » entre des zones de transparences différentes.

On utilise le filtre ainsi :

Dans cet exemple, on fabrique l’image typographique du #TITRE, puis on fait ressortir en rouge (ff0000 en RVB hexadécimal) les zones de contour, sur une épaisseur de 2 pixels.

(Si vous voulez utiliser une police semblable à celle de mon exemple, vous en trouverez plusieurs dans la rubrique « Stencil, Army » de dafont.com.)

Une astuce importance ici : lorsque l’on fabrique l’image typographique, on précise un padding, de façon à bien éloigner les lettres du bord de l’image ; de cette façon, le filtre de contour ne « débordera » pas de l’image.

On peut ensuite simplement superposer une typo de couleur et son contour, par exemple :

En inversant l’ordre des couches, on obtient un effet plus discret :

Notez bien : en réalité, la variable $trait (ici : 2) n’est pas réellement l’épaisseur d’un trait de contour. La fonction étant déjà très lourde en termes de temps de calcul, j’ai préféré la laisser telle quelle, certes imparfaite, mais fonctionnant bien.

Quant à la photographie en tête d’article, je l’obtiens en jouant avec le filtre image_podpod, qui justement fabrique des images transparentes à partir d’images non transparentes. Par exemple :

Sans trop de mal, on pourra aussi obtenir ceci :

ou ceci :

  • Avril 2006

    Je trouve pour ma part scandaleux qu’on propose au téléchargement une police « Army » !

  • ARNO*
    Avril 2006

    Mauvais souvenirs de corvée de ch... ?

  • Novembre 2006

    Bonjour, Merci beaucoup pour tous ces exemples très interessants, mais j’ai un souci avec le code suivant : ’fonction_imagecreatefrom’au niveau du script creer.

    Savez vous ce qui se passe ?

Qui êtes-vous ?
Votre message

Ce formulaire accepte les raccourcis SPIP [->url] {{gras}} {italique} <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.