Exemplos de sequências de caracteres: arte ASCII

Flash Player 9 e posterior, Adobe AIR 1.0 e posterior

Este exemplo de Arte ASCII mostra vários recursos para trabalhar com a classe String no ActionScript 3.0, incluindo o seguinte:

  • O método split() da classe String é usado para extrair valores de uma string delimitada por caracteres (informações de imagem em um arquivo de texto delimitado por tabulação).

  • Várias técnicas de manipulação de string, incluindo split() , concatenação e extração de uma parte da string usando substring() e substr() , são usadas para colocar a primeira letra de cada palavra em maiúscula nos títulos de imagem.

  • O método getCharAt() é usado para obter um único caractere de uma string (para determinar o caractere ASCII correspondente a um valor de bitmap em escala de cinza).

  • A concatenação de string é usada para criar a representação de arte ASCII de uma imagem com um caractere de cada vez.

O termo arte ASCII faz referência a representações de texto de uma imagem, na qual uma grade de caracteres de fonte monoespaçada, como caracteres Courier New, plotam a imagem. A imagem a seguir mostra um exemplo de arte ASCII produzida pelo aplicativo:

Arte ASCII - uma imagem renderizada com caracteres de texto
A versão da arte ASCII do gráfico é mostrada à direita.

Para obter os arquivos de aplicativo desse exemplo, consulte www.adobe.com/go/learn_programmingAS3samples_flash_br . Os arquivos do aplicativo ASCIIArt podem ser encontrados na pasta Amostras/AsciiArt. O aplicativo consiste nos seguintes arquivos:

Arquivo

Descrição

AsciiArtApp.mxml

ou

AsciiArtApp.fla

O arquivo principal do aplicativo no Flash (FLA) ou no Flex (MXML)

com/example/programmingas3/asciiArt/AsciiArtBuilder.as

A classe que fornece a funcionalidade principal do aplicativo, incluindo a extração de metadados da imagem de um arquivo de texto, carregamento de imagens e gerenciamento do processo de conversão de imagem para texto.

com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as

A classe que fornece o método parseBitmapData() para conversão de dados de imagem em uma versão String.

com/example/programmingas3/asciiArt/Image.as

Uma classe que representa uma imagem de bitmap carregada.

com/example/programmingas3/asciiArt/ImageInfo.as

Uma classe que representa metadados para uma imagem arte ASCII (como título, URL do arquivo de imagem, etc.)

imagem/

Uma pasta que contém imagens usadas pelo aplicativo.

txt/ImageData.txt

O arquivo de texto delimitado por tabulação que contém informações sobre as imagens a serem carregadas pelo aplicativo.

Extração de valores delimitados por tabulação

Este exemplo usa a prática comum de armazenar dados do aplicativo separados do próprio aplicativo. Dessa maneira, se os dados forem alterados (por exemplo, se outra imagem for adicionada ou um título da imagem for alterado) não haverá necessidade de recriar o arquivo SWF. Nesse caso, os metadados da imagem, incluindo o título da imagem, a URL do arquivo real da imagem e alguns valores que são usados para manipular a imagem são armazenados em um arquivo de texto (o arquivo txt\ImageData.ttx do projeto). O conteúdo do arquivo de texto é o seguinte:

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

O arquivo usa um formato delimitado por tabulação específico. A primeira linha é uma linha de título. As linhas restantes contêm os seguintes dados para cada bitmap a ser carregado:

  • O nome do arquivo do bitmap.

  • O nome de exibição do bitmap.

  • Os valores de limite de branco e de limite de preto dos bitmaps. Esses são valores hexadecimais acima e abaixo dos quais um pixel deve ser considerado completamente branco ou completamente preto.

Assim que o aplicativo é iniciado, a classe AsciiArtBuilder carrega e analisa o conteúdo do arquivo de texto para criar a “pilha” de imagens que irá exibir usando o seguinte código do método parseImageInfo() da 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); 
    } 
}

Todo o conteúdo do arquivo de texto é contido em uma única ocorrência de String, a propriedade _imageInfoLoader.data . Usando o método split() com o caractere de nova linha ( "\n" ) como um parâmetro, a ocorrência de String é dividida em uma matriz ( linhas ) cujos elementos são as linhas individuais do arquivo de texto. Em seguida, o código usa um loop para trabalhar com cada uma das linhas (exceto a primeira, porque ela contém apenas cabeçalhos em vez do conteúdo real). Dentro do loop, o método split() é usado uma vez novamente para dividir o conteúdo da única linha em um conjunto de valores (o objeto Array denominado imageProperties ). O parâmetro usado com o método split() nesse caso é o caractere de tabulação ( "\t" ), porque os valores de cada linha estão delineados por caracteres de tabulação.

Uso de método String para normalizar títulos de imagens

Uma da decisões de design desse aplicativo é que todos os títulos de imagens são exibidos usando um formato padrão, com a primeira letra de cada palavra colocada em maiúscula (exceto por algumas palavras que normalmente não são colocadas em maiúsculas em títulos em inglês). Em vez de assumir que o arquivo de texto contém títulos formatados de maneira apropriada, o aplicativo formata os títulos enquanto eles estão sendo extraídos do arquivo de texto.

Na listagem de código anterior, como parte da extração de valores individuais de metadados da imagem, a seguinte linha de código é usada:

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

Nesse código, o título da imagem do arquivo de texto é passado pelo método normalizeTitle() antes de ser armazenado no objeto 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(" "); 
}

Esse método usa o método split() para dividir o título em palavras individuais (separadas pelo caractere espaço), passa cada palavra pelo método capitalizeFirstLetter() e, em seguida, usa o método join() da classe Array para combinar as palavras em uma única string novamente.

Como o nome sugere, o método capitalizeFirstLetter() realmente faz o trabalho de colocar a primeira letra de cada palavra em maiúscula:

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

Em inglês, o caractere inicial de cada palavra em um título não será colocado em maiúscula se a palavra for uma das seguintes: “and”, “the”, “in”, “an”, “or”, “at”, “of” ou “a” (essa é uma versão simplificada das regras). Para executar essa lógica, o código primeiro usa uma declaração switch para verificar se a palavra é uma das palavras que não devem ser colocadas em letra maiúscula. Nesse caso, o código simplesmente ignora a declaração switch . Por outro lado, se a palavra precisar ser colocada em maiúscula, isso será feito em várias etapas, da seguinte maneira:

  1. A primeira letra da palavra é extraída usando substr(0, 1) que extrai uma substring a partir do caractere no índice 0 (a primeira letra da string, conforme indicado pelo primeiro parâmetro 0 ). A substring terá um caractere de comprimento (indicado pelo segundo parâmetro 1 ).

  2. Esse caractere é colocado em maiúscula usando o método toUpperCase() .

  3. Os caracteres restantes da palavra original são extraídos usando substring(1) que extrai uma substring no índice 1 (a segunda letra) até o final da string (indicado pela omissão do segundo parâmetro do método substring() ).

  4. A palavra final é criada combinando a primeira letra recém colocada em maiúscula com as letras restantes usando concatenação de strings: firstLetter + otherLetters .

Geração do texto de arte ASCII

A classe BitmapToAsciiConverter fornece a funcionalidade de converter uma imagem de bitmap em sua representação de texto ASCII. Esse processo é executado pelo método parseBitmapData() que é parcialmente mostrado aqui:

    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;

Esse código primeiro define uma ocorrência de String denominada result que será usada para criar a versão de arte ASCII da imagem de bitmap. Em seguida, ela executa loop pelos pixels individuais da imagem do bitmap de origem. Usando várias técnicas de manipulação de cores (omitidas aqui para resumir), ela converte os valores das cores vermelho, verde e azul de um pixel individual em um valor de escala de cinza único (um número de 0 a 255). Em seguida, o código divide esse valor por 4 (conforme mostrado) para convertê-lo em um valor na escala de 0 a 63 que é armazenado na variável index . (A escala de 0 a 63 é usada porque a “paleta” de caracteres ASCII disponíveis usado por esse aplicativo contém 64 valores.) A paleta de caracteres é definida como uma ocorrência de String na 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><+_~-;,. ";

Como a variável index define qual caractere ASCII na paleta corresponde ao pixel atual na imagem de bitmap, esse caractere é recuperado da String palette usando o método charAt() . Em seguida, ele é anexado à ocorrência da String result usando o operador de atribuição de concatenação ( += ). Além disso, no final de cada linha de pixels, um caractere de nova linha é concatenado ao final da String result , forçando uma quebra de linha para criar uma nova linha de “pixels” de caracteres.