Faire de l’ascii art à partir d’une image

Faire de l’ascii art à partir d’une image

02/01/2014

L​‌‍​‌​‌‍​‍’ASCII est le nom donné à une table informatique qui associe à des nombres une lettre de l’alphabet. Prononcé aski, cet acronyme signifie « American Standard Code for Information Interchange » et a aujourd’hui été étendu dans un but d’internationalisation dans un nouveau standard nommé UTF-8.

L’ASCII Art est quand à lui une manière de représenter en couleur ou en noir et blanc une image, en utilisant uniquement les caractères disponibles dans le code ASCII. Le personnage Catwoman de l’univers DC comics pourrait alors être représenté sous la forme suivante :

                 0                           M
8 D 0
M X0## M
7 MM 0MN7DXDXM# 0
#0MMM 00XMMM00MX0M8
#08MM 0M#77DD80M#MM
MM0# XT|D/:DNMMMM#D
#MN# TD|7D8XMMM0 #
8 MM00 DDT780#M#M
0MX0X D80###MX#0
X0T7MX X0XT/NX0M00MMN X
M00N8XM00X000XX0MM00MMMMM0M0 X
XMNT80XDXXM00MMMMMMM0MMMMMXMMN
#0D0MMMMMMMMMMMXDDX00M0MNM#MMM
M NMMM#M0XNX0MMXMMM0MMXMMX
0N888MMM000XMMMMMM0MMM#MNMT
M#M0NM0MMM000MMM0MMMM#MMM0M#
MM0MMMX000MMMMMMMMXM#MM#MD0M7
00MM000MMMMMMMMMMM#0 MD|0M
X DMM800MMMMM#MMMM0 D0NDM#
0 0MMD0MMMMM###M#M NM00#M
0 XMN8MMMMMMMM##X MMMM0
X #M07M#M#MMMM## 0MM#M
X0XMNMMMMMMMM# MM8MM
X MMM8DMMMMM#MM#M 80DMMM
0 |MM0D/TMMMMMMM0MM N0000
8M0XT.TNMMM##00M#0 #MMM
# 80MM0N700MM#MM778MM0 0M
X:#MMMMMX000MMMMMDDDNMMN
MMMM#MM000MMMMMMM0NX0M#0 #0
X#MMMM0MMMMMMMMMMMM00MM##M .T
DMMMM00MMMMMMM#MMMMMMMMM##M
##MM00MMM#########MMM######
#MNX########0 T###########M M
8#MN8M####### XX####M#MM#MX #
0MMMXXM#####| X0MM00MMM##M7 M.
##MM00#####7 N##M00MMM##M
##MMMM##### 0M##MMM####|

Nous allons donc voir dans ce tutoriel comment transformer une image en ASCII art, nous allons utiliser pour cela le langage de programmation PHP et sa librairie de manipulation d’image GD.

Une image numérique est un groupement de pixels en deux dimensions, chacun d’eux est d’une couleur. Chaque couleur est représentée par son niveau de rouge, de vert et de bleu.

Nous allons donc créer une fonction dans notre fichier php qui prendra en paramètre l’image à transformer, la gestion des couleurs, la longueur maximale de caractères par lignes et la liste des caractères à utiliser du plus clair au plus sombre.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
/**
* Transforme une image en chaine ASCII
* @param imagePath : Le chemin phisique de l'image
* @param colors : Gestion des couleurs ou non dans le r&eacute;sultat
* @param length : longueure maximal d'une ligne
* @param characters : liste des caract&egrave;res a utiliser, du plus claire au plus fonc&eacute;
* @return la chaine de caract&egrave;re du ASCII art, null si echec
*/
function getAsciiMapFromImage($imagePath, $colors = false, $length = 150, $characters = array(' ', '\'', '.', ':','|', '/', '7', 'T', 'D', '7', 'D', '8', 'N', 'X', '0', 'M','#'))
{
return null;
}

Pour commencer, il faut vérifier si l’image est présente sur le serveur et de la charger dans la mémoire de l’application pour ensuite déterminer la longueur et hauteur et déterminer le ratio de taille qui sera utilisé pour ne pas déformer l’image ou n’en utiliser qu’une partie.

Nous allons aussi inverser l’ordre de la liste de caractères de manière à économiser un calcul et aussi de placer sa cardinalité dans une variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
* Transforme une image en chaine ASCII
* @param imagePath : Le chemin phisique de l'image
* @param colors : Gestion des couleurs ou non dans le r&eacute;sultat
* @param length : longueure maximal d'une ligne
* @param characters : liste des caract&egrave;res a utiliser, du plus claire au plus fonc&eacute;
* @return la chaine de caract&egrave;re du ASCII art, null si echec
*/
function getAsciiMapFromImage($imagePath, $colors = false, $length = 150, $characters = array(' ', '\'', '.', ':','|', '/', '7', 'T', 'D', '7', 'D', '8', 'N', 'X', '0', 'M','#'))
{
if(file_exists($imagePath))
{
$image = imagecreatefromstring(file_get_contents($imagePath));
list($width, $height) = getimagesize($imagePath);

$scale = $width/$length;

$characters = array_reverse($characters);
$characters_count = count($characters);
$characters_last_elm = $characters_count - 1;
}
return null;
}

Il faut ensuite parcourir l’image pixel par pixel pour en extraire la couleur en ce point, en extraire chaque niveau de couleur, calculer la saturation de l’ensemble de manière à pouvoir déterminer le caractère qui correspond le mieux a l’intensité de teinte souhaitée.

Le caractère sera ensuite concaténé avec l’ensemble de la chaine sortante. À chaque fin de ligne on ajoutera le caractère de saut de ligne.

Si le paramètre de couleur est a vrai et qu’il de s’agit pas du caractère le plus clair, une balise span avec le style CSS représentant la couleur sera ajoutée.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
/**
* Transforme une image en chaine ASCII
* @param imagePath : Le chemin phisique de l'image
* @param colors : Gestion des couleurs ou non dans le r&eacute;sultat
* @param length : longueure maximal d'une ligne
* @param characters : liste des caract&egrave;res a utiliser, du plus claire au plus fonc&eacute;
* @return la chaine de caract&egrave;re du ASCII art, null si echec
*/
function getAsciiMapFromImage($imagePath, $colors = false, $length = 150, $characters = array(' ', '\'', '.', ':','|', '/', '7', 'T', 'D', '7', 'D', '8', 'N', 'X', '0', 'M','#'))
{
if(file_exists($imagePath))
{
$image = imagecreatefromstring(file_get_contents($imagePath));
list($width, $height) = getimagesize($imagePath);

$scale = $width/$length;

$characters = array_reverse($characters);
$characters_count = count($characters);
$characters_last_elm = $characters_count - 1;

$return_string = '';

for($y = 0; $y &lt;= $height - $scale - 1; $y += $scale) {
for($x = 0; $x &lt;= $width - ($scale / 2) - 1; $x += ($scale / 2)) {
$rgb = imagecolorat($image, $x, $y);
$red = (($rgb &gt;&gt; 16) &amp; 0xFF);
$green = (($rgb &gt;&gt; 8) &amp; 0xFF);
$blue = ($rgb &amp; 0xFF);
$sat = ($red + $green + $blue) / (255 * 3);
$char = $characters[ (int)( $sat * $characters_last_elm ) ];
if($colors &amp;&amp; $char != $characters[$characters_last_elm])
$return_string.= '&lt;span style="color:rgb('.$red.', '.$green.', '.$blue.');"&gt;'.$char.'&lt;/span&gt;';
else
$return_string.= $char;
}
$return_string .= PHP_EOL;
}

return $return_string;
}
return null;
}

Vous pouvez maintenant admirer votre ASCII Art en appelant la fonction sur l’image de votre choix à la taille que vous souhaitez.

1
2
<!– Utilisation dun balise pre de mannière a ne pas perdre les saut de ligne et les espaces –>
<pre><?php echo getAsciiMapFromImage(‘robin.jpg’, true, 60);?></pre>

Ce tutoriel ainsi que les scripts utilisables sont sous licence Creative Common suivante : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/.