Esempi di stringhe: ASCII art

Flash Player 9 e versioni successive, Adobe AIR 1.0 e versioni successive

L'esempio ASCII Art illustra varie funzionalità della classe String in ActionScript 3.0, incluso le seguenti:

  • Metodo split() della classe String, utilizzato per estrarre valori da una stringa delimitata da caratteri (informazioni di immagine in un file di testo delimitato da tabulazione).

  • Varie tecniche di manipolazione delle stringhe, incluso il metodo split() , la concatenazione e l'estrazione di una porzione della stringa mediante i metodi substring() e substr() , che possono essere utilizzate per rendere maiuscola la prima lettera ogni parola nei titoli delle immagini.

  • Metodo getCharAt() , che consente di ottenere un solo carattere da una stringa (per determinare il carattere ASCII corrispondente a un valore bitmap in scala di grigi).

  • La concatenazione di stringhe, utilizzata per creare la rappresentazione ASCII art di un'immagine, un carattere per volta.

Il termine ASCII art si riferisce a rappresentazioni di immagini sotto forma di testo, nelle quali una griglia di caratteri a spaziatura fissa, quali Courier New, va a formare l'immagine. L'illustrazione seguente riporta un esempio di ASCII art prodotto dall'applicazione:

ASCII art - rendering di un'immagine con caratteri di testo
La versione ASCII art dell'immagine è riportata sulla destra.

Per ottenere i file dell'applicazione per questo esempio, visitate la pagina www.adobe.com/go/learn_programmingAS3samples_flash_it . I file dell'applicazione ASCIIArt si trovano nella cartella Samples/AsciiArt. L'applicazione è composta dai seguenti file:

File

Descrizione

AsciiArtApp.mxml

o

AsciiArtApp.fla

Il file principale dell'applicazione in Flash (FLA) o Flex (MXML)

com/example/programmingas3/asciiArt/AsciiArtBuilder.as

Classe che fornisce le funzionalità principali dell'applicazione, inclusa l'estrazione dei metadati dell'immagine da un file di testo, il caricamento delle immagini e la gestione del processo di conversione immagine-testo.

com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as

Classe che fornisce il metodo parseBitmapData() per la conversione dei dati immagini in versione stringa.

com/example/programmingas3/asciiArt/Image.as

Classe che rappresenta un'immagine bitmap caricata.

com/example/programmingas3/asciiArt/ImageInfo.as

Classe che rappresenta metadati di un'immagine ASCII art (quali titolo, URL file di immagine e così via).

image/

Cartella contenente immagini utilizzate dall'applicazione.

txt/ImageData.txt

File di testo delimitato da tabulazione contenente informazioni sulle immagini da caricare mediante l'applicazione.

Estrazione di valori delimitati da tabulazione

In questo esempio viene utilizzato il sistema molto diffuso di memorizzare i dati dell'applicazione in una posizione separata rispetto all'applicazione stessa; in questo modo, se i dati vengono modificati (ad esempio, se viene aggiunta una nuova immagine o se il titolo di un'immagine viene modificato), non sarà più necessario ricreare il file SWF. In questo caso, i metadati dell'immagine, incluso il titolo dell'immagine, l'URL del file dell'immagine vero e proprio e alcuni valori utilizzati per manipolare l'immagine sono memorizzati in un file di testo (il file txt/ImageData.txt del progetto). Il file di testo contiene quanto segue:

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

Il file impiega un formato specifico delimitato da tabulazione. La prima riga è una riga di intestazione. Le restanti righe contengono i seguenti dati per ciascuna bitmap da caricare:

  • Il nome file della bitmap.

  • Il nome di visualizzazione della bitmap.

  • I valori di soglia del bianco e soglia del nero per le bitmap. Si tratta di valori esadecimali al di sopra o al di sotto dei quali un pixel viene considerato completamente bianco o completamente nero.

Non appena l'applicazione viene avviata, la classe AsciiArtBuilder carica ed analizza il contenuto del file di testo per creare uno “stack” di immagini da visualizzare mediante il seguente codice del metodo parseImageInfo() della 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); 
    } 
}

Tutto il contenuto del file di testo è racchiuso in una sola istanza di String, la proprietà _imageInfoLoader.data . Utilizzando il metodo split() con il carattere nuova riga ( "\n" ) come parametro, l'istanza String viene divisa in un array ( lines ) i cui elementi sono singole righe del file di testo. Quindi, il codice impiega un ciclo per lavorare con ogni singola riga (tranne la prima, che contiene solo l'intestazione). All'interno del ciclo, il metodo split() viene utilizzato di nuovo per dividere il contenuto della singola riga in una serie di valori (l'oggetto Array chiamato imageProperties ). Il parametro utilizzato con il metodo split() in questo caso è il carattere tabulazione ( "\t" ), in quanto i valori di ogni riga sono delimitati dalla tabulazione.

Uso dei metodi della classe String per normalizzare i titoli delle immagini

Una delle decisioni di progettazione di questa applicazione è che tutti i titoli delle immagini vengano visualizzati in un formato standard, con la prima lettera di ogni parola in maiuscolo (tranne che per alcune parole che generalmente non vengono scritte in maiuscolo nei titoli). Anziché dare per scontato che il file di testo contenga titoli formattati correttamente, l'applicazione formatta i titoli mentre vengono estratti dal file di testo.

Nell'elenco di codice precedente, viene utilizzata la riga seguente per estrarre valori metadati dalle singole immagini:

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

In questo codice, il titolo dell'immagine viene trasmesso dal file di testo attraverso il metodo normalizeTitle() prima di essere memorizzato nell'oggetto 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(" "); 
}

Questo metodo impiega il metodo split() per dividere il titolo in singole parole (separate dal carattere spazio), passa ogni singola parola attraverso il metodo capitalizeFirstLetter() , quindi usa il metodo join() della classe Array per combinare le parole di nuovo in un'unica stringa.

Come suggerisce il nome, il metodo capitalizeFirstLetter() consente di rendere maiuscola la prima lettera di ogni parola:

    /** 
     * 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; 
    }

In inglese, la lettera iniziale di ciascuna parola di un titolo non verrà resa maiuscola se la parola in questione è una delle seguenti: “and”, “the”, “in”, “an”, “or”, “at”, “of” o “a” (questa è una versione semplificata delle regole). Per eseguire questa logica, il codice impiega un'istruzione switch per verificare se la parola è tra quelle che non devono essere scritte in maiuscolo. In tal caso, il codice salta semplicemente l'istruzione switch. Se invece la parola deve essere scritta in maiuscolo, l'operazione di trasformazione viene eseguita in varie fasi:

  1. La prima lettera della parola viene estratta mediante la funzione substr(0, 1) , che consente di estrarre una sottostringa che inizia con il carattere in posizione di indice 0 (la prima lettera della stringa, come indicato dal primo parametro 0 ). La sottostringa è lunga un solo carattere (indicato dal secondo parametro 1 ).

  2. Tale carattere viene scritto in maiuscolo utilizzando il metodo toUpperCase() .

  3. I caratteri rimanenti della parola originale vengono estratti mediante la funzione substring(1) , che consente di estrarre una sottostringa che inizia nella posizione di indice 1 (seconda lettera) fino alla fine della stringa (indicato dalla non impostazione del secondo parametro del metodo substring() ).

  4. La parola viene creata combinando la prima lettera trasformata in maiuscolo con le restanti lettere mediante concatenazione della stringa: firstLetter + otherLetters.

Creazione di testo ASCII art

La classe BitmapToAsciiConverter fornisce la funzionalità di conversione di un'immagine bitmap nella sua rappresentazione di testo ASCII. Tale procedura viene eseguita dal metodo parseBitmapData() , parzialmente illustrato di seguito:

    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;

Questo codice definisce in primo luogo un'istanza di String denominata result che verrà utilizzata per creare la versione ASCII art dell'immagine bitmap. Quindi, esegue una funzione ciclica attraverso i singoli pixel dell'immagine bitmap di origine. Mediante una serie di tecniche di manipolazione del colore (qui omesse per ragioni di brevità), i valori di rosso, verde e blu di ogni singolo pixel vengono convertiti in un solo valore in scala di grigi (un numero compreso tra 0 e 255). Il codice divide quindi tale valore per 4 (come illustrato) per convertirlo in un valore della scala che va da 0 a 63, memorizzata nella variabile index . (Viene utilizzata una scala da 0 a 63 perché la “tavolozza” dei caratteri ASCII disponibili per questa applicazione contiene 64 valori.) La tavolozza di caratteri viene definita come un'istanza di String nella 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><+_~-;,. ";

Poiché la variabile index definisce quale carattere ASCII nella tavolozza corrisponde al pixel corrente dell'immagine bitmap, tale carattere viene recuperato dalla stringa palette mediante il metodo charAt() . Quindi, esso viene aggiunto all'istanza di String result mediante l'operatore di assegnazione della concatenazione ( += ). Inoltre, alla fine di ogni riga di pixel, un carattere nuova riga viene concatenato alla fine della stringa result , per obbligare la riga a tornare a capo e creare una nuova riga di “pixel” di caratteri.