Contactez-nous

1

Un habillage irrégulier (float : ragged)

17 mars 2006
par ARNO*
[SPIP 1.9 et GD2] Voici un nouveau filtre SPIP qui vous permettra de réaliser un effet que nous attendons depuis des années en HTML (et qui n'est pas prêt d'arriver sous la forme d'un style facile à utiliser), réalisable en bidouillant mais pour lequel il n'existait pas encore d'automatisme (à ma connaissance). (Attention: cet article est désormais [complété par un second article->87]; les explications qui suivent sont nécessaires à la compréhension de ce nouvel article.) Le but est de réaliser un «habillage» irrégulier autour d'une image. Comme vous le savez, en HTML, lorsqu'on insère une image à l'intérieur d'un texte, en l'alignant à droite ou à gauche, le texte «habille» l'image selon les bords du {rectangle:} Le filtre qui suit va nous permettre de réaliser l'habillage en fonction de la forme réelle de l'image: {{{Principe de l'habillage irrégulier}}} Le principe général de l'habillage irrégulier est celui de [Curvelicious->http://www.meyerweb.com/eric/css/edge/raggedfloat/demo.html] d'Eric Meyer. Ce que notre script va réaliser, c'est l'étape suivante, puisque l'effet pourra dès lors être réalisé {automatiquement}: le filtre va analyser l'image pour fabriquer le découpage. - {{Première étape: ne pas utiliser l'image pour créer l'habillage}} Nous insérons l'image dans la page, mais sans réaliser d'habillage. Le texte et l'image sont superposés. ([Eric Meyer->http://www.meyerweb.com/eric/css/edge/raggedfloat/demo.html] propose, lui, de découper l'image en tranches (à éviter absolument!). [FlumpCakes->http://flumpcakes.co.uk/css/chef-curv] place l'image en background. ) Notre script va se contenter d'insérer l'image dans un
flottant de largeur nulle, l'image étant ensuite positionnée à l'intérieur, en position absolue. À tester, mais l'avantage est pouvoir afficher correctement les images PNG~24 avec couche alpha (que nous utiliserons ici) dans MSIE, comme [nous l'avons déjà expliqué->68]. - {{Insérer des petits rectangle horizontaux successifs pour créer l'habillage}} Nous allons maintenant réaliser l'habillage en insérant une série de
successifs dont le code sera le suivant:
L'astuce est dans la suite float: right; clear: right; (right devenant simplement left si on veut aligner l'image à gauche): on insère un élément flottant, et chaque élément flottant chasse l'autre). De cette façon, on «empile» des rectangles horizontaux, dont la hauteur totale sera égale à la hauteur de l'image. On créé un espace «flottant» irrégulier destiné à «recouvrir» les parties de l'image que l'on souhaite habiller. On «recouvre» avec des blocs invisibles, évidemment. Si l'on recouvrait avec des blocs colorés, voici ce qu'on obtiendrait: Le gnou n'est ajouté que pour comprendre la forme des
: ce sont ces
successifs (empilés) qui provoquent l'habillage irrégulier du texte, et non l'image (rectangulaire) du gnou. (Note: j'ai ajouté overflow: hidden; dans mes
; sans lui, j'obtenais des rectangles trop grands sous MSIE. Cédric, dans le forum ci-dessous, indique qu'il s'agit de la taille de la police qui «force» la hauteur des boîtes; même si le
ne contient aucun texte.) {{{Automatiser la découpe}}} Ce principe est plutôt simple, mais sans automatisme, il n'est vraiment pas utilisable... C'est sans doute la raison pour laquelle le truc de Curvelicious ne se rencontre presque jamais sur le Web. Le script suivant va nous permettre de {créer automatiquement la série de rectangles empilés}, en faisant analyser par SPIP la forme de l'image. Je vous donne le script tout de suite: function image_float ($img, $align, $margin=10) { $image = valeurs_image_trans($img, "float-$align", "php"); if (!$image) return(""); $w = $image["largeur"]; $h = $image["hauteur"]; $precision = round($h / 5); $im = $image["fichier"]; $dest = $image["fichier_dest"]; $creer = $image["creer"]; $ret .= "
"; if ($creer) { include_spip('inc/logos'); // bicoz presence reduire_image $nouveau = valeurs_image_trans(reduire_image($im, 0, $precision),""); $im_n = $nouveau["fichier"]; $x_i = $nouveau["largeur"]; $y_i = $nouveau["hauteur"]; $rapport = ($w / $x_i); $im_n = $image["fonction_imagecreatefrom"]($im_n); // une premiere passe // pour recuperer les valeurs for ($j = 0; $j < $y_i; $j++) { $transp = true; for ($i = 0; $i < $x_i && $transp; $i++) { if ($align == "right") $rgb = ImageColorAt($im_n, $i+1, $j); else $rgb = ImageColorAt($im_n, ($x_i - $i)-1, $j); $a = ($rgb >> 24) & 0xFF; if ($a > 125) $larg[$j] ++; else $transp = false; } } $larg[-1] = $w; $larg[$y_i] = $w; // une deuxieme passe // pour appliquer les valeurs // en utilisant les valeurs precedente et suivante for ($j = 0; $j < $y_i; $j++) { $reste = ($precision - $j); $haut_rest = $h - $haut_tot; $hauteur = round(($haut_rest) / $reste); $haut_tot = $haut_tot + $hauteur; $resultat = min($larg[$j-1],$larg[$j],$larg[$j+1]); $forme .= "\n
"; } // Ajouter un div de plus en dessous $forme .= "\n
"; // Sauvegarder le fichier $handle = fopen($dest, 'w'); fwrite($handle, $forme); fclose($handle); $ret .= $forme; } else { $ret .= join(file($dest),""); } return $ret; }
C'est un filtre qui s'applique à n'importe quelle image: logo ou document joint dans un portfolio. Pour mon exemple, le code dans le squelette est très simple: [(#FICHIER|image_float{right,5})]

Lorem ipsum dolor sit amet ...

Évidemment, vous ne travaillez certainement pas uniquement avec un document joint intitulé «GNU»... Les deux variables de image_float sont: -- l'alignement left ou right (on place l'image à gauche ou à droite); -- l'espacement en pixels du texte par rapport à l'image. Il est très important de noter ici que l'habillage va se baser sur le {transparence} de l'image. Cela ne concerne donc que les images GIF ou PNG, dont le filtre va analyser les informations de transparence. (On peut cependant très facilement adapter ce filtre pour qu'il réalise le détourage en fonction d'une couleur de référence -- blanc par exemple.) {{{Le code expliqué}}} Je n'entrerai pas dans les détails, je me contenterai d'exposer le fonctionnement général (le code est, par ailleurs, plutôt simple une fois qu'on en a compris le principe). Le travail principal se trouve à l'intérieur du test: if ($creer) { Ici le code intéressant... } -- Pour commencer, nous travaillons sur une image $nouveau qui est une version dont les dimensions sont réduites par 5 de l'image d'origine. Pourquoi 5? Parce que nous voulons des rectangles de 5 pixels de haut. Cette valeur peut être modifiée en début de script, à la ligne qui indique: $precision = round($h / 5); Cette réduction va nous économiser beaucoup de temps et de puissance (25 fois moins de calculs). -- Voici réellement le principe du script: for ($j = 0; $j < $y_i; $j++) { $transp = true; for ($i = 0; $i < $x_i && $transp; $i++) { if ($align == "right") $rgb = ImageColorAt($im_n, $i+1, $j); else $rgb = ImageColorAt($im_n, ($x_i - $i)-1, $j); $a = ($rgb >> 24) & 0xFF; if ($a > 125) $larg[$j] ++; else $transp = false; } } On parcourt l'image réduite ligne par ligne (chaque ligne deviendra un div). Pour chaque ligne, on commence par le premier pixel (à droite ou à gauche selon l'alignement qu'on a choisi), et on parcourt cette ligne jusqu'à tomber sur un pixel non transparent. Ainsi, pour chaque ligne $j, on connaît {le nombre de pixels transparents} $larg[$j] avant de «tomber» sur les pixels non transparents de l'image. -- Une seconde boucle va appliquer ces valeurs en créant l'empilement de
. for ($j = 0; $j < $y_i; $j++) { $resultat = min($larg[$j-1],$larg[$j],$larg[$j+1]); $forme .= "\n
"; }
À chaque ligne, on récupère dans $resultat la valeur $larg minimale de la ligne actuelle, de la ligne précédente et de la ligne suivante. (Pourquoi pas la moyenne? Pour éviter que le texte ne «rentre» dans l'image.) Ensuite, à chaque ligne, la largeur du
est calculée selon la largeur totale de l'image $w diminuée de $resultat, le nombre de pixels transparents (on multiplie le chiffre final, puisqu'on travaille sur une image réduite). Si vous comparez avec le script complet, vous verrez que j'ai masqué dans l'extrait précédent les lignes suivantes: $reste = ($precision - $j); $haut_rest = $h - $haut_tot; $hauteur = round(($haut_rest) / $reste); $haut_tot = $haut_tot + $hauteur; Ces lignes (que l'on peut simplifier et améliorer) permettent de calculer la hauteur de chaque
. En gros, chaque rectangle doit faire 5 pixels de haut mais, avec les arrondis, cela ne tombe que rarement juste. En réalité, ces lignes sont plus utiles dans les cas où l'on modifie le calcul de la $precision en début de script. Ici, la précision est calculée de façon à ce que les rectangles aient toujours 5 pixels de haut, le nombre de ces rectangles pouvant varier en fonction de la hauteur de l'image. On peut aussi décréter que la précision sera une valeur fixe, par exemple 20, ce qui signifie alors qu'il y aura 20 rectangles superposés, quelle que soit la hauteur de l'image. -- Enfin, toute une partie du script, au début et à la fin, est liée à la création d'un fichier de cache, pour éviter de recalculer à chaque fois cette série de valeurs. Là où les filtres graphiques de SPIP stockent en général l'image filtrée, ici on stocke tout simplement le code HTML de la série de rectangles. ----- {{{Et voici le résultat}}}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus ut nunc eget ante ornare nonummy. Ut arcu. Duis tincidunt tincidunt quam. In elementum blandit odio. Nullam ultrices. Nulla sem augue, mollis id, vulputate eget, ullamcorper ultrices, purus. Aenean porttitor odio at mauris. Mauris quis enim vitae purus dictum ultricies. Proin pharetra lectus auctor lacus. Quisque at sem ac lectus ornare vehicula. Nunc pulvinar, leo ut tristique auctor, felis diam gravida neque, consectetuer cursus sem nisl ut enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec justo. Aliquam erat volutpat. Sed vel enim nec tellus suscipit imperdiet. Maecenas sagittis, dolor id tincidunt suscipit, orci tortor fermentum mi, id varius dolor nisi quis lectus. Quisque ante sem, molestie a, euismod sed, tempus sit amet, mauris. Integer vel ante eget urna sagittis consectetuer. Quisque ullamcorper convallis velit.

Ut porta. Quisque euismod. Cras adipiscing, tellus id vestibulum ultrices, leo erat auctor diam, vitae aliquam libero orci ac augue. Fusce vel dui. Sed eleifend est ac mauris. Nam in leo. In hac habitasse platea dictumst. Suspendisse hendrerit nisl at orci. Curabitur condimentum. Proin scelerisque. Nunc eros.

  • izo
    Mars 2006

    J’adore :) .... bravo

  • Cedric (cedric chez yterium.com)
    Mars 2006

    Trop fort ! Les boites trop hautes sous IE j’ai deja rencontré ca aussi : c’etait la hauteur de la police qui limitait la hauteur mini de la boite ...

  • ARNO*
    Mars 2006

    Les boites trop hautes sous IE j’ai deja rencontré ca aussi : c’etait la hauteur de la police qui limitait la hauteur mini de la boite ...

    OK, merci pour l’info. Je modifie ce passage dans l’article.

  • Nicolas Hoizey
    Mars 2006

    Incroyable !

    Est-ce qu’à ton avis une adaptation (native ou plugin) pour gérer de la même façon les images incluses dans le corps d’un article aurait un sens ? Par exemple, pouvoir enrichir la syntaxe <img12|right> pour avoir <img12|right|detoure>.

  • ARNO*
    Mars 2006

    Est-ce qu’à ton avis une adaptation (native ou plugin) pour gérer de la même façon les images incluses dans le corps d’un article aurait un sens ?

    À mon sens, la meilleure solution consisterait plutôt à gérer les insertions d’images et de documents (<img|xxx> et autres) via des morceaux de squelettes. À la façon, désormais, des formulaires, que l’on peut ainsi personnaliser dans son propre jeux de squelettes.

  • cy_altern
    Mars 2006

    Il est très important de noter ici que l’habillage va se baser sur le transparence de l’image. Cela ne concerne donc que les images GIF ou PNG, dont le filtre va analyser les informations de transparence. (On peut cependant très facilement adapter ce filtre pour qu’il réalise le détourage en fonction d’une couleur de référence — blanc par exemple.)

    donc, pour automatiser un peu plus on devrait pouvoir passer la background-color de la page, ce qui permet de ne pas avoir à gérer la transparence dans l’image à détourer

  • ARNO*
    Mars 2006

    pour automatiser un peu plus on devrait pouvoir passer la background-color de la page

    C’est ça. Ça n’est pas bien méchant à programmer (mais je vous laisse bosser un peu quand même...).

    En revanche, ce qui devient plus enquiquinant, c’est l’affichage de l’image (ici le gnou). Comme c’est, pour l’instant, un float, elle apparaît au-dessus du texte qui suit. Et comme l’image n’est pas transparente, il y a alors comme un problème.

  • cy_altern
    Mars 2006

    En revanche, ce qui devient plus enquiquinant, c’est l’affichage de l’image (ici le gnou). Comme c’est, pour l’instant, un float, elle apparait au-dessus du texte qui suit. Et comme l’image n’est pas transparente, il y a alors comme un probleme.

    pour contourner ce probleme, on peut mettre l’image en background-image : vu qu’il s’agit de pouvoir utiliser des images sans transparence (donc jpg), on n’a pas besoin du hack de MSIE pour les png.

  • ARNO*
    Mars 2006

    cy_altern : j’ai bossé la question, et je livre une solution dans un second article. La solution du background-image dans un grand #container n’est pas viable, puisque le filtre ne peut agir que localement (alors que le div #container doit contenir même le texte qui suit).

  • Nicolas Hoizey
    Mars 2006

    la meilleure solution consisterait plutôt à gérer les insertions d’images et de documents ( et autres) via des morceaux de squelettes

    Je crois qu’on est déjà quelques-uns à en rêver depuis quelque temps.

    Il faudrait pour cela modulariser un peu plus "propre()", à priori, et là y’a du boulot.

  • mortimer
    Mars 2006

    Bravo Arno* !!! ça fait un moment que j’en rève de celui là. Mais qu’estce que cela donne quand on desactive les css ?

    Je crois qu’on est déjà quelques-uns à en rêver depuis quelque temps.

    Il faudrait pour cela modulariser un peu plus "propre()", à priori, et là y’a du boulot.

    en fait, le plugin "modèle" est un début de travail dans ce sens. Si j’ai bien compris, il ne lui manque pas grand chose.

  • ARNO*
    Mars 2006

    Mais qu’estce que cela donne quand on desactive les css ?

    Question imprécise : ça veut dire quoi, « désactiver les CSS » : ne pas charger un fichier CSS externe, ou bien carrément filtrer (ou ne pas appliquer) les informations de maquette des styles ?

    - D’abord, toutes les informations relevant du style sont directement codées dans les <div>, et ne dépendent pas d’un appel à une classe de style ; du coup, si l’idée est de ne pas charger un fichier CSS externe, ça fonctionne toujours.

    - Imaginons, dans tous les cas, ne pas accepter les informations relevant du style.

    • Si l’image est en PNG 24 avec transparence (cet article), alors l’image est de toute façon insérée en tant qu’<img...> à l’endroit du filtre ; donc au pire on affiche l’image sans habillage. Pour son positionnement, c’est un style float qui est appliqué, donc ça dépend de ce que tu entends par « désactiver les CSS » ;
    • si l’image n’est pas transparente (article suivant), l’image est codée en tant que background des div de détourage ; donc fortes chances qu’elle n’apparaisse pas.
  • Septembre 2006

    Bonjour,

    j’ai vu sur un site sur les css, un exemple pour réaliser "un habillage irrégulier" ; 100% css et sans javascript ; Allez sur ce site et vous n’en croirez pas vos yeux ... des effets spéciaux, des slides show incroyables et pleins d’autres choses !!!

    http://www.cssplay.co.uk/index.html

  • ARNO*
    Septembre 2006

    Merci pour l’info. La page en question est là.

    Mais ça reste une variante des sites que j’ai déjà référencés. Ça reste quasiment inutilisable, puisqu’il faut calculer et insérer les boîtes à la main.

    L’idée de mon filtre, ici, est à la fois d’utiliser ces systèmes de boîtes, mais surtout de faire calculer ces boîtes et de les insérer automatiquement.

  • micmac
    Septembre 2006

    Voilà je me demandais comment faire passer la contrib de A List Apart dans une fonction de spip. Je crois que le principe est sensiblement le même. Bon travail donc.

    http://www.alistapart.com/articles/sandbags

    Un peu HS mais ce site est une mine et je signale aussi cet article qui propose une mise en page photo élégante, on frôle la PAO.

    http://www.alistapart.com/articles/magazinelayout

  • ARNO*
    Septembre 2009

    Salut Micmac,

    Oui, c’est en gros la méthode de l’article « Sandbags » de A List Apart. Mais ma méthode a été publiée quelques mois avant l’article en question. :-))

  • Paul
    Décembre 2010

    Bon, je viens de passer un long moment à m’essayer à cette manip sans réslutat :(, en mm tps je connais rien en php donc a part copier le script dans un fichier "script_detoure.php" et l’appeler [(#EMBED_DOCUMENT|image_floatright,5|image_reduire150|script_detoure)] rien ne fonctionne, pas meme le image_float avec spip 2.1.2 ?

    Merci d’avance si ayuda est possible :)

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.