Exemple de chaîne : ASCII Art

Flash Player 9 et les versions ultérieures, Adobe AIR 1.0 et les versions ultérieures

Cet exemple ASCII Art représente différentes façons d’utiliser la classe String en ActionScript 3.0, notamment :

  • La méthode split() de la classe String est utilisée pour extraire des valeurs d’une chaîne séparée par des caractères (informations d’image dans un fichier de texte séparé par des tabulations).

  • Plusieurs techniques de manipulation de chaînes, y compris split(), la concaténation et l’extraction d’une partie de la chaîne à l’aide de substring() et de substr(), sont utilisées pour mettre la première lettre de chaque mot dans les titres d’image en majuscule.

  • La méthode getCharAt() est utilisée pour obtenir un seul caractère à partir d’une chaîne (pour déterminer le caractère ASCII correspondant à une valeur bitmap d’échelle de gris).

  • La concaténation de chaîne est utilisée pour construire la représentation ASCII art d’une image, un caractère à la fois.

Le terme ASCII art fait référence à des représentations textuelles d’une image dans lesquelles une grille de polices de caractères à espacement constant (caractères Courier New, par exemple) trace l’image. L’image suivante est un exemple d’ASCII art produit par l’application :

ASCII art : image rendue à l’aide de caractères de texte
La version ASCII art du graphique est illustrée à droite.

Pour obtenir les fichiers d’application de cet exemple, voir www.adobe.com/go/learn_programmingAS3samples_flash_fr. Les fichiers de l’application ASCIIArt se trouvent dans le dossier Samples/AsciiArt. L’application se compose des fichiers suivants :

Fichier

Description

AsciiArtApp.mxml

ou

AsciiArtApp.fla

Fichier d’application principal en FLA pour Flash ou en MXML pour Flex

com/example/programmingas3/asciiArt/AsciiArtBuilder.as

La classe qui fournit la fonctionnalité principale de l’application, notamment l’extraction de métadonnées d’image d’un fichier de texte, le chargement des images et la gestion du processus de conversion d’image en texte.

com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as

Une classe qui fournit la méthode parseBitmapData() pour convertir des données d’image dans une version String.

com/example/programmingas3/asciiArt/Image.as

Une classe qui représente une image bitmap chargée.

com/example/programmingas3/asciiArt/ImageInfo.as

Une classe représentant des métadonnées pour une image ASCII art (titre, URL de fichier image, etc.).

image/

Un dossier contenant des images utilisées par l’application.

txt/ImageData.txt

Un fichier de texte séparé par des tabulations et contenant des informations sur les images à charger par l’application.

Extraction de valeurs séparées par des tabulations

Cet exemple utilise le stockage séparé de données d’application par rapport à l’application ; de cette façon, si les données changent (par exemple, si une autre image est ajoutée ou que le titre d’une image change), il est inutile de recréer le fichier SWF. Dans ce cas, les métadonnées d’image, y compris le titre de l’image, l’URL du fichier d’image réel et certaines valeurs utilisées pour manipuler l’image, sont stockés dans un fichier de texte (le fichier txt/ImageData.txt dans le projet). Le contenu du fichier de texte est le suivant :

FILENAME    TITLE    WHITE_THRESHHOLD    BLACK_THRESHHOLD 
FruitBasket.jpg    Pear, apple, orange, and banana    d8    10 
Banana.jpg    A picture of a banana    C8    20 
Orange.jpg    orange    FF    20 
Apple.jpg    picture of an apple    6E    10

Le fichier utilise un format séparé par des tabulations spécifique. La première ligne est une ligne d’en-tête. Les lignes restantes contiennent les données suivantes pour chaque bitmap à charger :

  • Le nom de fichier du bitmap.

  • Le nom d’affichage du bitmap.

  • Les valeurs de seuil du blanc et les valeurs de seuil du noir pour les bitmaps. Il s’agit de valeurs hexadécimales au-dessus et en dessous desquelles un pixel doit être considéré comme totalement blanc ou totalement noir.

Dès que l’application démarre, la classe AsciiArtBuilder se charge et analyse le contenu du fichier de texte afin de créer la « pile » d’images qu’elle chargera. Pour cela, elle utilise le code suivant de la méthode parseImageInfo() de la classe AsciiArtBuilder :

var lines:Array = _imageInfoLoader.data.split("\n"); 
var numLines:uint = lines.length; 
for (var i:uint = 1; i < numLines; i++) 
{ 
    var imageInfoRaw:String = lines[i]; 
    ... 
    if (imageInfoRaw.length > 0) 
    { 
        // Create a new image info record and add it to the array of image info. 
        var imageInfo:ImageInfo = new ImageInfo(); 
 
        // Split the current line into values (separated by tab (\t) 
        // characters) and extract the individual properties: 
        var imageProperties:Array = imageInfoRaw.split("\t"); 
        imageInfo.fileName = imageProperties[0]; 
        imageInfo.title = normalizeTitle(imageProperties[1]); 
        imageInfo.whiteThreshold = parseInt(imageProperties[2], 16); 
        imageInfo.blackThreshold = parseInt(imageProperties[3], 16); 
        result.push(imageInfo); 
    } 
}

Le contenu entier du fichier de texte se trouve dans une seule occurrence de String, la propriété _imageInfoLoader.data. Vous pouvez utiliser la méthode split() avec le caractère de nouvelle ligne ("\n") comme paramètre pour diviser l’occurrence de String en un tableau (lines) dont les éléments sont les lignes individuelles du fichier de texte. Le code utilise ensuite une boucle pour travailler avec chacune des lignes (excepté la première car elle contient uniquement des en-têtes). A l’intérieur de la boucle, la méthode split() est de nouveau utilisée pour diviser le contenu de la ligne en un ensemble de valeurs (l’objet Array appelé imageProperties). Le paramètre utilisé avec la méthode split() dans ce cas est le caractère de tabulation ("\t") car les valeurs dans chaque ligne sont délimitées par des tabulations.

Utilisation de méthodes String pour normaliser des titres d’image

Dans cette application, tous les titres d’image sont affichés à l’aide d’un format standard, avec la première lettre de chaque mot en majuscule (excepté quelques mots qui ne sont généralement pas en majuscule dans des titres anglais). Au lieu de considérer que le fichier de texte contient des titres formatés correctement, l’application formate les titres lors de leur extraction du fichier de texte.

Dans la liste de code précédente, lors de l’extraction de valeurs de métadonnées d’image individuelles, la ligne de code suivante est utilisée :

        imageInfo.title = normalizeTitle(imageProperties[1]);

Dans ce code, le titre de l’image issu du fichier de texte est transmis au moyen de la méthode normalizeTitle() avant d’être stocké dans l’objet ImageInfo :

private function normalizeTitle(title:String):String 
{ 
    var words:Array = title.split(" "); 
    var len:uint = words.length; 
    for (var i:uint; i < len; i++) 
    { 
        words[i] = capitalizeFirstLetter(words[i]); 
    } 
     
    return words.join(" "); 
}

Cette méthode utilise la méthode split() pour diviser le titre en mots individuels (séparés par le caractère d’espacement), transmet chaque mot au moyen de la méthode capitalizeFirstLetter() puis utilise la méthode join() de la classe Array pour combiner de nouveau les mots en une chaîne unique.

Comme son nom l’indique, la méthode capitalizeFirstLetter() met la première lettre de chaque mot en majuscule :

    /** 
     * Capitalizes the first letter of a single word, unless it's one of 
     * a set of words that are normally not capitalized in English. 
     */ 
    private function capitalizeFirstLetter(word:String):String 
    { 
        switch (word) 
        { 
            case "and": 
            case "the": 
            case "in": 
            case "an": 
            case "or": 
            case "at": 
            case "of": 
            case "a": 
                // Don't do anything to these words. 
                break; 
            default: 
                // For any other word, capitalize the first character. 
                var firstLetter:String = word.substr(0, 1); 
                firstLetter = firstLetter.toUpperCase(); 
                var otherLetters:String = word.substring(1); 
                word = firstLetter + otherLetters; 
        } 
        return word; 
    }

En anglais, le premier caractère des mots suivants utilisés dans un titre n’est pas mis en majuscule : “and,” “the,” “in,” “an,” “or,” “at,” “of,” ou “a.” (il s’agit d’une version simplifiée des règles). Pour exécuter cette logique, le code utilise d’abord une instruction switch pour vérifier si le mot est l’un des mots ne devant pas être en majuscule. Si c’est le cas, le code sort de l’instruction switch. Si le mot doit être en majuscule, la procédure comprend plusieurs étapes :

  1. La première lettre du mot est extraite à l’aide de substr(0, 1), qui extraie une sous-chaîne commençant par le caractère au niveau de l’index 0 (la première lettre de la chaîne, comme indiqué par le premier paramètre 0). La sous-chaîne contiendra un caractère (indiqué par le deuxième paramètre 1).

  2. Ce caractère est mis en majuscule à l’aide de la méthode toUpperCase().

  3. Les caractères restants du mot d’origine sont extraits à l’aide de substring(1), qui extraie une sous-chaîne commençant à l’index 1 (la deuxième lettre) jusqu’à la fin de la chaîne (indiqué en omettant le deuxième paramètre de la méthode substring()).

  4. Le dernier mot est créé en combinant la première lettre mise en majuscule et les lettres restantes en utilisant la concaténation de chaîne : firstLetter + otherLetters

Génération du texte ASCII art

La classe BitmapToAsciiConverter permet de convertir une image bitmap en sa représentation de texte ASCII. Cette procédure est effectuée par la méthode parseBitmapData(), partiellement représentée ici :

    var result:String = ""; 
     
    // Loop through the rows of pixels top to bottom: 
    for (var y:uint = 0; y < _data.height; y += verticalResolution) 
    { 
        // Within each row, loop through pixels left to right: 
        for (var x:uint = 0; x < _data.width; x += horizontalResolution) 
        { 
            ... 
 
            // Convert the gray value in the 0-255 range to a value 
            // in the 0-64 range (since that's the number of "shades of 
            // gray" in the set of available characters): 
            index = Math.floor(grayVal / 4); 
            result += palette.charAt(index); 
        } 
        result += "\n"; 
    } 
    return result;

Ce code définit d’abord une occurrence de String appelée result qui sera utilisée pour créer la version ASCII art de l’image bitmap. Il effectue ensuite une boucle sur les pixels de l’image bitmap source. Il utilise plusieurs techniques de manipulation des couleurs (non décrites ici) pour convertir le rouge, le vert et le bleu d’un pixel en une valeur d’échelle de gris (un nombre entre 0 et 255). Le code divise ensuite cette valeur par 4 (comme indiqué) pour la convertir en une valeur dans l’échelle 0-63, qui est stockée dans la variable index (l’échelle 0-63 est utilisée car la palette des caractères ASCII disponibles utilisée par cette application contient 64 valeurs). La palette des caractères est définie en tant qu’occurrence de String dans la classe BitmapToAsciiConverter :

// The characters are in order from darkest to lightest, so that their 
// position (index) in the string corresponds to a relative color value 
// (0 = black). 
private static const palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. ";

Etant donné que la variable index définit le caractère ASCII de la palette qui correspond au pixel actuel dans l’image bitmap, ce caractère est récupéré de la palette String à l’aide de la méthode charAt(). Il est ensuite ajouté à l’occurrence de String result au moyen de l’opérateur d’affectation de concaténation (+=). En outre, à la fin de chaque ligne de pixels, un caractère de nouvelle ligne est concaténé à la fin de l’occurrence de String result afin que la ligne à renvoyer crée une ligne de pixels de caractères.