Пример строк: ASCII-графика

Flash Player 9 и более поздних версий, Adobe AIR 1.0 и более поздних версий

Этот пример ASCII-графики демонстрирует ряд возможностей работы с классом String в ActionScript 3.0, включая следующее.

  • Метод split() класса String используется для получения значений из строки, разделенной символами (графическая информация в файле с разделителем-табуляцией).

  • Чтобы написать с большой буквы каждое слово в названиях изображений, используется несколько приемов манипуляции со строками, включая метод split(), сцепление и извлечение части строки с помощью методов substring() и substr().

  • Метод getCharAt() используется для получения одного символа из строки (чтобы определить символ ASCII, соответствующий значению растрового изображения в оттенках серого).

  • Сцепление строк используется, чтобы построить ASCII-представление изображения символ за символом.

Термином ASCII-графика называется текстовое представление изображения, в котором рисунок выстраивается в виде сетки символов моноширинного шрифта, такого как Courier New. Ниже приводится пример ASCII-графики, созданный приложением.

ASCII-графика — изображение, представленное с помощью символов
Версия изображения, созданного с помощью ASCII-графики, находится справа.

Получить файлы приложения для этого примера можно на странице www.adobe.com/go/learn_programmingAS3samples_flash_ru. Файлы приложения ASCIIArt находятся в папке Samples/AsciiArt. Приложение состоит из следующих файлов.

File

Описание

AsciiArtApp.mxml

или

AsciiArtApp.fla

Основной файл приложения Flash (FLA) или Flex (MXML)

com/example/programmingas3/asciiArt/AsciiArtBuilder.as

Класс, обеспечивающий основные функции приложения, включая извлечение метаданных изображения из текстового файла, загрузку изображений, управление процессом преобразования изображения в текст.

com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as

Класс, обеспечивающий метод parseBitmapData() для преобразования данных изображения в версию класса String.

com/example/programmingas3/asciiArt/Image.as

Класс, представляющий загруженное растровое изображение.

com/example/programmingas3/asciiArt/ImageInfo.as

Класс, представляющий метаданные для изображения ASCII-графики (например, название, URL-адрес файла с изображением и т.д.).

image/

Папка, содержащая изображения, используемые приложением.

txt/ImageData.txt

Текстовый файл с разделителем-табуляцией, содержащий сведения об изображениях, предназначенных для загрузки приложением.

Получение значений, разделенных табуляцией

В этом примере используется общепринятая практика, при которой данные приложения хранятся отдельно от самого приложения. Таким образом, если данные изменяются (например, при добавлении другого изображения или при изменении названия изображения), не требуется повторно создавать SWF-файл. В этом случае метаданные изображения, включая название, URL-адрес файла с изображением и некоторые значения, используемые для манипуляций с изображением) хранятся в текстовом файле (файл txt/ImageData.txt в проекте). Ниже приводится содержимое текстового файла:

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

Файл использует специальный формат с разделителем-табуляцией. Первая строка является строкой заголовка. Остальные строки содержат следующие денные для каждого растрового изображения, предназначенного для загрузки:

  • имя файла с растровым изображением;

  • отображаемое имя растрового изображения;

  • пороговые значения для белого и черного цветов в растровом изображении; это шестнадцатеричные значения, выше и ниже которых пиксел считается полностью белым или черным соответственно.

Как только запускается приложение, класс AsciiArtBuilder загружает и анализирует содержимое текстового файла, чтобы создать «стопку» изображений для показа с использованием следующего кода из метода parseImageInfo() класса 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); 
    } 
}

Все содержимое текстового файла добавлено в один экземпляр String, в свойство _imageInfoLoader.data. С помощью метода split(), в качестве параметра которого используется символ новой строки ("\n") экземпляр String разбивается в массив (lines), элементы которого представляют собой отдельные строки текстового файла. Затем код использует цикл для обработки каждой строки (кроме первой, так как она включает только заголовки, а не содержимое). Внутри цикла еще раз используется метод split(), чтобы разбить содержимое одной строки с целью получения группы значений (объект Array с именем imageProperties). В этом случае в качестве параметра метода split() используется символ табуляции ("\t"), так как значения в каждой строке разделяются символами табуляции.

Использование методов класса String для нормализации заголовков изображений

Одним из решений дизайна для этого приложения является отображение названий изображений с использованием стандартного формата англоязычных заголовков, в котором каждое слово пишется с большой буквы (за исключением немногих слов, на которые это правило не распространяется). Не ожидая, что текстовый файл содержит заголовки в правильном формате, приложение форматирует их в момент получения из текстового файла.

В предыдущем коде в процессе получения метаданных отдельного изображения используется следующая строка:

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

В этом коде заголовок изображения из текстового файла передается методу normalizeTitle() и только после этого сохраняется в объекте 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(" "); 
}

Этот метод вызывает метод split() для деления заголовка на несколько слов (разделенных пробелом), передает каждое слово методу capitalizeFirstLetter(), а затем использует метод join() класса Array для повторного объединения отдельных слов в строку.

Метод capitalizeFirstLetter() делает первую букву слова заглавной.

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

В английском языке в заголовках не пишутся с заглавной буквы следующие слова: «and», «the», «in», «an», «or», «at», «of» и «a». (Это упрощенная версия правила.) Следуя этой логике, код сначала использует инструкцию switch, чтобы проверить, не является ли слово исключением и его не нужно писать с заглавной буквы. Если это так, код просто покидает инструкцию switch. С другой стороны, если слово должно быть написано с заглавной буквы, выполняются следующие действия.

  1. Первая буква слова извлекается с помощью метода substr(0, 1), который получает подстройку с начальным индексом символа 0 (первая буква в строке, на что указывает первый параметр 0). Подстрока будет содержать один символ (о чем говорит второй параметр 1).

  2. Этот символ переводится в верхний регистр с помощью метода toUpperCase().

  3. Остальные символы исходного слова извлекаются с помощью метода substring(1), который получает подстроку начиная с индекса 1 (вторая буква) до конца строки (на что указывает отсутствие второго параметра в методе substring()).

  4. Окончательная версия слова создается путем объединения заглавной первой буквы с остальными посредством сцепления строк: firstLetter + otherLetters.

Создание текста ASCII-графики

Класс BitmapToAsciiConverter обеспечивает возможность преобразования растрового изображения в текстовое представление с использованием символов ASCII. Этот процесс выполняется методом parseBitmapData(), фрагмент которого представлен ниже.

    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;

Сначала код определяет экземпляр String с именем result, который будет использоваться для построения ASCII-графики для растрового изображения. Затем выполняется циклическая обработка отдельных пикселов исходного растрового изображения. Используя несколько приемов манипуляции с цветами (опущенных здесь для краткости), код преобразует значения красного, зеленого и синего цветов отдельного пиксела в одно значение оттенка серого (число от 0 до 255). После этого код делит это значение на 4 (как показано в примере), чтобы преобразовать его в диапазон 0-63, и сохраняет полученное число в переменной index. (Используется диапазон от 0 до 63, так как «палитра» доступных символов ASCII, используемых этим приложением, составляет 64 значения.) Палитра символов определяется как экземпляр String в классе 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><+_~-;,. ";

Переменная index определяет, какой символ ASCII соответствует текущему пикселу растрового изображения, и требуемый символ извлекается из экземпляра String с именем palette с помощью метода charAt(). Затем он добавляется в экземпляр String с именем result с помощью оператора сложения с присвоением (+=). Кроме того, в конце каждого ряда пикселов к экземпляру result добавляется символ новой строки, чтобы перенести строку и начать новый ряд символов-«пикселов».