示例:ASCII 字符图

此 ASCII 字符图示例说明了可以在 ActionScript 3.0 中使用 String 类实现的大量功能,其中包括:

“ASCII 字符图”这一术语指的是图像的文本表示形式,即使用等宽字体字符(如 Courier New 字符)的网格来绘制图像。下图便是该应用程序所生成 ASCII 字符图的一个例子:


显示 ASCII 字符图示例输出的图像:一幅梨子的图像以及旁边用 ASCII 字符创建的梨子图像。

图形的 ASCII 字符图版本显示在右侧。


要获取该范例的应用程序文件,请访问 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在文件夹 Samples/AsciiArt 下找到 ASCIIArt 应用程序文件。该应用程序包含以下文件:

文件

说明

AsciiArtApp.mxml

AsciiArtApp.fla

Flash (FLA) 或 Flex (MXML) 中的主应用程序文件

com/example/programmingas3/asciiArt/AsciiArtBuilder.as

此类提供了应用程序主要功能,包括了从文本文件中提取图像元数据、加载图像和管理图像到文本的转换过程等功能。

com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as

此类提供了用于将图像数据转换为字符串版本的 parseBitmapData() 方法。

com/example/programmingas3/asciiArt/Image.as

此类表示所加载的位图图像。

com/example/programmingas3/asciiArt/ImageInfo.as

此类表示 ASCII 字符图像的元数据(如标题、图像文件 URL 等)。

image/

此文件夹包含应用程序使用的图像。

txt/ImageData.txt

此制表符分隔的文本文件中包含与应用程序要加载的图像有关的信息。

子主题

提取由制表符分隔的值
使用 String 的方法标准化图像标题
生成 ASCII 字符图文本

提取由制表符分隔的值

此示例使用了将应用程序数据与应用程序本身分开存储的通行做法;通过这种方式,在数据发生更改时(例如,添加了另一幅图像或更改了图像标题),无需重新创建该 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 类将加载并分析文本文件的内容,以便创建它要显示的图像的“堆栈”,执行这些操作时使用 AsciiArtBuilder 类的 parseImageInfo() 方法中的如下代码:

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)
    {
        // 创建一条新的图像信息记录并将其添加到图像信息数组中。
        var imageInfo:ImageInfo = new ImageInfo();

        // 将当前行分割为由制表符 (\t) 分隔的多个值
        // 并且提取出各个属性:
        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 实例分割到一个 Array (lines) 中,数组元素为文本文件的各个行。然后,代码使用一个循环处理每行(第一行除外,因为它只包含标题而不包含实际内容)。在循环内部,再一次使用 split() 方法将每行的内容分割到一组值(名为 imageProperties 的 Array 对象)中。在本例中,用于 split() 方法的参数为制表符 (\t),因为每行中的值均由制表符进行分隔。

使用 String 的方法标准化图像标题

此应用程序的设计目标之一便是使用一种标准格式显示所有图像标题,即标题中每一个单词的第一个字母均为大写形式(在英文标题中通常不大写的少数单词除外)。应用程序并不假定文本文件已经包含格式正确的标题,它在从文本文件中提取标题时对标题格式进行设置。

在前面的代码清单中,使用了如下代码行来提取每个图像元数据值:

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

在该代码中,来自文本文件的图像标题在存储到 ImageInfo 对象之前先传递给 normalizeTitle() 方法进行处理:

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() 方法进行处理,接着使用 Array 类的 join() 方法将单词重新合并为一个字符串。

如同其名称所表达的含义,capitalizeFirstLetter() 方法实际执行将每个单词的第一个字母变为大写形式的工作:

    /**
     * 将单个单词的第一个字母变为大写形式,除非该单词属于
     * 英语中通常不大写的一组单词之一。
     */
    private function capitalizeFirstLetter(word:String):String
    {
        switch (word)
        {
            case "and":
            case "the":
            case "in":
            case "an":
            case "or":
            case "at":
            case "of":
            case "a":
                // 不对这些单词执行任何操作。
                break;
            default:
                // 对于其它任何单词,则会将其第一个字符变为大写形式。
                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 = "";
    
    // 自上向下遍历所有像素行:
    for (var y:uint = 0; y < _data.height; y += verticalResolution)
    {
        // 在每一行中,自左向右遍历所有像素:
        for (var x:uint = 0; x < _data.width; x += horizontalResolution)
        {
            ...

            // 将位于 0-255 范围内的灰度值转换为
            // 介于 0-64 之间的一个值(因为这是可用字符集合中的
            // “灰度梯度”数目):
            index = Math.floor(grayVal / 4);
            result += palette.charAt(index);
        }
        result += "\n";
    }
    return result;

此代码首先定义一个名为 result 的 String 实例,将使用它来构建位图图像的 ASCII 字符图版本。然后,它遍历源位图图像的每个像素。通过使用若干颜色处理技术(为了简便起见,此处省略了对这些技术的介绍),它将每个像素的红色、绿色和蓝色值转换为单个灰度值(一个介于 0-255 之间的数字)。接着,代码将该值除以 4(如下所示)以将其转换为介于 0-63 之间的一个值,此值存储在变量 index 中。(之所以使用 0-63 的范围是因为此应用程序使用的可用 ASCII 字符的“调色板”包含 64 个值。)该字符调色板在 BitmapToAsciiConverter 类中定义为一个 String 实例:

// 字符按从最暗到最亮的顺序排列,所以它们
// 在字符串中的位置(索引)对应于一个相对颜色值
// (0 = 黑色)。
private static const palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. ";

由于变量 index 定义调色板中的哪个 ASCII 字符对应于位图图像中的当前像素,可使用 charAt() 方法从 palette 字符串中检索该字符。然后,使用连接赋值运算符 (+=) 将其追加到 result 字符串实例。此外,在每行像素的末尾,会将一个换行符连接到 result 字符串的末尾,强制该行换行以创建新的一行字符“像素”。


Flash CS3

 

评论添加到页面后给我发送电子邮件 | 评论报告

当前页: http://livedocs.adobe.com/flash/9.0_cn/main/00000086.html