Saaaaluuuut p’tit geek du code email ! Je t’ai concocté un article rien que pour toi : je vais te parler dans cet article de la conversion d’image en pur code HTML et CSS dans un email. Comment m’est venue cette idée ? Je t’explique : je réfléchis souvent, au moment de m’endormir, à des sujets d’article. En voici un qui me trainait dans la tête : comment optimiser le rendu des images dans un email en Dark Mode ? Après je fais toujours le même rêve : je nage dans la Seine et tout d’un coup, j’avale un rat. Alors j’étouffe et pis je coule. En bas, y a des huitres, elles m’attrapent les chevilles. Alors je vomis le rat sur les huîtres, le rat il attaque les huîtres, je remonte à la surface, j’prends une péniche sur la tête et là, j’me réveille.
Le lendemain, je recevai un email de la marque « IRO », que j’ouvrai sur mon téléphone portable, configuré en dark mode. L’exemple était tout trouvé. Je m’appuierai donc, dans cet article, sur la marque IRO.
Table des matières
Explication de la conversion d’une image en code HTML et CSS
Le principe est le suivant : dans un ou plusieurs tableaux (<table>
), chaque cellule (<td>
) représente un pixel de l’image sélectionnée. Sur ces cellules seront appliquées des correctifs CSS pour en garantir la largeur et la hauteur (1px
), ainsi qu’un attribut HTML bgcolor
pour renseigner une couleur de fond à la cellule. Si des cellules soeurs ont une couleur de fond similaire, l’attribut colspan
avec la valeur correspondante est appliquée pour pouvoir limiter le nombre de cellules dans chaque ligne, et donc, le code HTML final.
On se rapproche donc trèèès fortement, sur le principe, du pixel art, forme d’art numérique consistant à créer des images à partir de petits éléments carrés appelés « pixels ». À la différence que le pixel art s’amuse surtout à « créer » des images sans se soucier de la netteté, alors que notre volonté dans cet article est de « reproduire » le plus fidèlement possible une image avec une cellule pour chaque pixel de l’image originale.
Les avantages d’une image convertie en code HTML et CSS
Un rendu sur Dark Mode optimisé
Pour rappel, seuls les formats JPEG, GIF et PNG sont correctement supportés sur l’intégralité des environnements d’ouverture. SVG, WEBP, AVIF, BASE 64, BMP, HDR, HEIF, PPM, TIFF sont bons pour le rebut. Et les formats supportés ne se convertissent pas automatiquement en Dark Mode. Pourquoi ? Mais tout simplement parce qu’ils ne sont pas « vectoriels », pardi !
Le problème d’une image, c’est qu’en Dark Mode dans un email, elle restera la même. Autrement dit, une image d’un logo noir sur fond transparent restera un logo noir sur fond transparent en Dark Mode. Mais si la cellule comprenant votre image a un fond blanc en Light Mode, comment se comportera-t-elle en Dark Mode ? Je vous le donne en mille : le fond deviendra sombre, et votre logo ne sera alors plus visible/lisible. À moins d’y ajouter une ombre portée ou une bordure de la même couleur que la couleur de fond de votre cellule…
On pourrait donc être tenté de concevoir ses images entièrement en HTML et en CSS, à la manière du pixel art, pour que les codes couleurs hexadécimaux soient automatiquement convertis sur le paramètre Dark Mode activé. C’est légitime, non ?
Bref, c’est pour cette problématique, entre autre, qu’il peut être intéressant de se pencher sur la conversion de l’image en code HTML et CSS. Car alors, tous les codes hexadécimaux de vos cellules seront convertis. Et votre logo s’affichera alors blanc (en principe) sur fond sombre.
Affichage immédiat du visuel
Vous le connaissez bien ce message, hein ? Un « cauchemar » pour nombre d’email marketeurs. Imaginez un monde où il ne serait plus nécessaire d’appuyer sur le bouton « Afficher le contenu distant dans ce message » pour afficher les visuels de votre email… Ça ne serait pas beau ça, hm ? Et je ne vous parle pas de mettre les images en pièces jointes, non non. Ça c’est sale. Je vous parle d’images codées en HTML et en CSS, qui s’afficheraient donc instantanément dans votre email.
C’est bien le cas d’ailleurs dans le code ici développé pour IRO : nul besoin d’images hébergées ! Du code HTML et zou ! Le logo est affiché. « Il est gouleyant. Il a de la cuisse, il attaque sèchement le palais, il manque pas de retour. Vous pouvez servir ! »
Accessibilité optimisée grâce à des ressources externes limitées
Question d’accessibilité, honnêtement, il y a un avantage. Petit, certes, mais il est là : le fait de pouvoir afficher une image sans téléchargement obligatoire des images. Et donc, en réduisant aussi le nombre de ressources à télécharger. Et aussi parce que, comme mentionné ci-dessus, le rendu en Dark Mode est optimisé.
Les inconvénients de la conversion d’une image en code HTML et CSS
Poids du fichier HTML généré à la conversion
Moooon-Dieu-Noël-ma-mère ! J’ai mal à mon code ! Étant donné que chaque pixel correspond à une cellule de tableau, forcément, le poids d’un simple visuel de 31px de large sur 35px de haut, simplement en noir et blanc, est déjà bien conséquent. J’en veux pour preuve, Mesdames et Messieurs les jurés, que la seule lettre « R » codée avec cette méthode atteint le poids pharamineux de 32,6ko ! C’est tout de même assez conséquent.
Bon, si le poids du code HTML de nos emailings chéris n’était pas contraint, je dirai : soyons fous ! Au diable l’avarice ! Mais c’est mal connaître le monde facétieux de l’email marketing : Gmail, Orange… Ils sont nombreux à « couper » un email sitôt qu’une limite de poids est atteinte. Autant vous dire qu’avec trois simples lettres de, respectivement, 8,19ko, 32,6ko, et 43,1ko, et un poids total (accrochez-vous bien) de 83,89ko, la marge de manœuvre reste très faible. D’autant que le code généré n’est pas indenté, et optimisé au maximum pour en alléger le poids ! C’est dire !
Limitations de design
Vous l’aurez compris (ou peut-être pas, je ne peux pas vous en vouloir) : pour obtenir un code relativement léger, il vous faudra appliquer cette conversion sur des images « basiques », simples, comprenant peu de couleurs, et pas trop grandes. D’où mon conseil suivant : cela ne peut s’appliquer que sur des logos ou des icônes. Et avec parcimonie. Ce n’est pas pour rien que l’exemple choisi dans cet article est le logo IRO, épuré et minimaliste au possible.
Préférez aussi des images avec un contraste suffisant, pour que le script de conversion soit en mesure de distinguer chaque pixel lors de son exécution.
Besoin d'aide ?
Lire du contenu ne fait pas tout. Le mieux, c’est d’en parler avec nous.
Hyperlien impossible à appliquer
C’est là un joli petit piège : pour concevoir ces images en HTML et CSS, j’utilise des tableaux (<table>
). Or, ces tableaux sont des éléments de type table
. Or, un élément de type inline
, comme le <a>
, ne peut pas englober un élément de type table
. Non seulement cela n’est pas correct HTMLement parlant, mais cela peut aussi générer des problématiques de rendu ou d’utilisation. Oubliez donc le fait de pouvoir insérer un lien sur votre logo : désormais, plus moyen de le rendre cliquable. Vous pouvez essayer, mais vous risquez de vous y casser les dents… « Mets ta bouche sur le bord du trottoir… »
Accessibilité du code HTML après conversion
Oui, je mets à la fois l’accessibilité dans les avantages ET les inconvénients. Pourquoi ? Parce que même si l’image est automatiquement téléchargée et lisible par tous, elle ne permet pas d’avoir un texte alternatif. Donc, si le rendu est déformé, aucune possibilité de comprendre le sens de la conception. Vous comprenez ?
De plus, les lecteurs d’écran considèreront, par défaut, cette création comme un tableau HTML de présentation. Vous devrez probablement, comme le recommande Mark Robbins sur l’utilisation du format SVG dans un email, spécifier un attribut role
avec la valeur img
sur votre tableau comprenant le code HTML, et y inclure un élément <title>
pour y renseigner un texte alternatif.
<table cellpadding="0" cellspacing="0" border="0" role="img">
<tr>
<td>
<title>Alt text</title>
[your HTML code]
</td>
</tr>
</table>
Et j’aime autant vous dire que je ne réponds pas de l’insertion d’une balise <title>
dans un <table>
!
Mise à jour du visuel
Autant changer un logo ou une image au format PNG, JPG ou GIF est relativement rapide (il vous suffit de modifier le visuel en question sur votre outil de design ou plateforme de prototypage, de l’exporter, de l’héberger puis de changer le chemin de la balise img dans le code HTML), autant changer un logo/visuel au format HTML et CSS demande un peu plus de travail :
- Mise à jour du visuel
- Exportation du visuel
- Modification du script
- Exécution du script
- Optimisation du test généré si besoin
- Test du code généré
- Application du code dans le fichier HTML final…
Gardez cela en mémoire, c’est un point non négligeable !
Méthodologie à adopter
Bonnes pratiques
- Ne cherchez pas à effectuer ce type de transformation sur des visuels complexes, très larges, ou avec beaucoup de couleurs.
- Privilégiez les visuels extrêêêêmement simples, type logo ou icône.
- Dans ce dernier cas, préparez un visuel propre à cette conception sur la plateforme de prototypage de votre choix, pour simplifier au maximum du maximum le design du logo.
- Ne cherchez pas à effectuer cette conversion « manuellement », cela vous prendra beaucoup trop de temps : n’oubliez pas qu’une simple image de 31px de large sur 35px de haut comprend, je pose 3 et je retiens 8 : 31*35=1085 pixels. Donc, autant de cellules à créer. Bon courage !
Des outils pour convertir une image en code HTML et CSS
J’ai eu beau chercher des plateformes proposant la conversion d’images en tableaux HTML avec mise en forme inline du CSS, j’ai fait chou blanc ! J’étais pourtant persuadé d’avoir utilisé ce type de service il y a encore 4 ou 5 ans. Mais soit.
J’ai alors créé moi-même mon convertisseur. Enfin, moi-même, entendons-nous : avec l’aide de l’intelligence artificielle. J’ai donc demandé à ChatGPT quel langage permettrait cette prouesse : selon lui, Python ferait l’affaire. Je lui demande alors de me créer un script Python pour aboutir à cette conversion, et de m’expliquer comment exécuter le script (car, au cas où j’aurai besoin de le préciser, je n’ai aucune connaissance en Python). J’avoue que… Je me sens un nain au milieu des géants… Voici le code du script optimisé :
from PIL import Image
# Write below the name of the HTML file to be produced instead of image_table.html
def image_to_html_table(image_path, output_html='image_table.html', cell_size=1):
# Open the image
image = Image.open(image_path)
image = image.convert('RGB')
# Get the dimensions of the image
width, height = image.size
# Convert the image into a list of pixels
pixels = list(image.getdata())
pixels = [pixels[i * width:(i + 1) * width] for i in range(height)]
# Start the HTML table with 'role="presentation"'
html = '<table cellpadding="0" cellspacing="0" border="0" role="presentation">'
# Process each row of pixels
for row in pixels:
html += '<tr>'
current_color = None
colspan = 1
for pixel in row:
r, g, b = pixel
color = f'#{r:02x}{g:02x}{b:02x}'
if color == current_color:
colspan += 1
else:
if current_color:
style = f'width:{cell_size * colspan}px; height:{cell_size}px; font-size:1px; line-height:1px;'
if current_color != '#ffffff':
html += f'<td bgcolor="{current_color}" style="{style}" colspan="{colspan}"> </td>'
else:
html += f'<td style="{style}" colspan="{colspan}"> </td>'
current_color = color
colspan = 1
# Add the last sequence of pixels in the row
if current_color is not None:
style = f'width:{cell_size * colspan}px; height:{cell_size}px; font-size:1px; line-height:1px;'
if current_color != '#ffffff':
html += f'<td bgcolor="{current_color}" style="{style}" colspan="{colspan}"> </td>'
else:
html += f'<td style="{style}" colspan="{colspan}"> </td>'
html += '</tr>'
html += '</table>'
# Write the HTML table to a file
with open(output_html, 'w') as file:
file.write(html)
# Example of function usage
# Write below the name or path of your .jpg file in place of image.jpg
image_to_html_table('image.jpg')
Et, c’est cadeau, voici les étapes à suivre pour exécuter ce script, dans le cas où vous souhaiteriez le tester ou l’implémenter de votre côté. Tu peux garder la monnaie, ça m’dérange pas… :
- Copiez ce code et collez-le dans un nouveau fichier sur Notepad++.
- Faites les modifications nécessaires dans le script : changez le nom du fichier HTML à générer, changer le nom et/ou le chemin de l’image concernée…
- Enregistrez le fichier au format .py (par exemple, script_conversion.py) dans un dossier nommé « generateur » sur votre Bureau.
- Depuis votre ordinateur :
- Sous Windows, cliquez sur le bouton de recherche en bas à gauche de l’écran; puis tapez
cmd
et appuyez sur « Entrée ». Cela ouvre une fenêtre noire dans laquelle vous pouvez taper des instructions de commande. - Sur Mac, ouvrez l’application « Terminal ». Vous pouvez la trouver en utilisant « Spotlight ».
- Sous Windows, cliquez sur le bouton de recherche en bas à gauche de l’écran; puis tapez
- Dans la fenêtre noire, utilisez la commande
cd
suivie du chemin vers le dossier où se trouve le script. Par exemple, si le script est sur le Bureau, tapezcd Bureau
(pour Windows) oucd Desktop
(sur Mac) et appuyez sur Entrée. - Toujours dans la fenêtre noire, tapez
pip install Pillow
pour installer la bibliothèque Pillow. - Puis allez jusqu’au dossier comprenant votre script, en tapant par exemple
cd Bureau
, puiscd generateur
. - Enfin, exécutez le script en tapant
python script_conversion.py
et appuyez sur « Entrée ». - Votre image est alors, normalement, convertie dans un fichier HTML en tableaux et cellules HTML dans votre dossier « generateur ».
Testez le code généré
Après une initiative de ce genre, je vous le dis tout de suite : il vaut mieux tester ! J’ai eu beau créer mon propre générateur, ajouter les propriétés CSS font-size
et line-height
avec pour valeur 1px
, l’adapter pour en optimiser le code de sortie… mes résultats finaux de rendu selon les environnements d’ouverture ne sont pas tout à fait convaincants : largeur étrange sur le début de la lettre « R », léger décalage sur la lettre « O », déformation sur Gmail App ou sur le logiciel Outlook 2021 sur Windows 11… Je suis loin d’un rendu parfait ! Pourtant le logo sélectionné était on-ne-peut-plus simple…
Et je ne peux définitivement pas me contentes d’un tel rendu. Vous non plus d’ailleurs. Non. non non ! LE MONDE EST EN TRAIN DE DEVENIR CINGLÉ ! Y A PERSONNE À PART MOI QUI SE SOUCIE ENCORE DE RESPECTER LES RÈGLES ? 😀
Conclusion : est-il judicieux de convertir une image en tableaux et cellules HTML et CSS ?
Je pense que le moment est venu de vous dire ce que j’ai appris, d’en tirer une conclusion, non ? Après bien des cafés (froids), de multiples tests et tentatives d’optimisation de script, mes conclusions sont les suivantes :
- Convertir une image en langages HTML et CSS peut être intéressant si vous parvenez à réduire au maximum le poids du code généré, et que le rendu est testé et approuvé. Cependant, cela ne règle aucunement les problématiques d’accessibilité et de clic/lien impossible à appliquer.
- Ce type de manipulation ne peut se faire que sur des visuels extrêêêêmement simples graphiquement parlant : logos, icônes…
- Je penche pour un abandon de cette solution au regard du poids généré, qu’il me semble difficile de réduite drastiquement. Et j’envisage plutôt une adaptation du logo en texte (lorsqu’il s’agit d’un logo principalement « textuel ») avec une typo websafe la plus proche possible : il y a des contraintes dans l’emailing, on peut très bien imaginer avoir des recommandations dès le début de la conception email (logo, icône) avec ce type de suggestion, non ?
- Si vous souhaitez rester sur une méthode traditionnelle, la conception d’un logo au format PNG avec fond transparent et un minimum de travail pour un rendu correct en Dark Mode (bordure ou ombre portée de la même couleur que la couleur de fond de la cellule) fera très bien l’affaire aussi.
- Dans un monde idéal, je chercherai une solution combinant un format d’image SVG avec solution de repli dans le cas où le format SVG ne serait pas supporté. Je vous invite d’ailleurs à découvrir l’article de Mark Robbins au sujet du format SVG dans les emails.
Nota bene : je ne suis clairement pas un expert en script Python. Je n’y connais même rien, pour être franc. Aussi, je penche pour une optimisation du script et du code généré. Je suis donc tout à l’écoute sur vos conseils, avis, et recommandations !
2 réponses
Hé ben dit donc Thomas, quelle énergie sur ce sujet rarement traité 🙂 et bien traité d’ailleurs !!
Merci Bruno ! J’y ai mis de l’énergie, car je suis toujours intrigué par ce type de test, de R&D 🙂 Malheureusement, les conclusions que je tire de ces tests me font dire que ce n’est pas forcément une solution à adopter 😀 En tout cas, merci pour ton commentaire !