效果:
=>ImageInfo.as
package com.cen.programmingas3.asciiArt
{
/**
* 位图信息类:包含位图的相关信息;
* @author cen
*/
public class ImageInfo
{
/**
* constructor
*/
public function ImageInfo()
{
}
/**
* 类属性*/
/*文件名称*/
public var fileName:String;
/*文件标题*/
public var title:String;
/*白色阀值*/
public var whiteThreshold:uint;
/*黑色阀值*/
public var blackThreshold:uint;
}
}
=>Image.as
package com.cen.programmingas3.asciiArt
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLRequest;
/**
* 位图图像类
* @author cen
*/
public class Image extends EventDispatcher
{
/**
* 私有变量*/
/*Loader 类可用于加载 SWF文件或图像(JPG、PNG 或 GIF)文件。使用 load()方法来启动加载。被加载的显示对象将作为 Loader对象的子级添加。*/
private var _loader:Loader;
/**
* 公共属性*/
/*位图*/
public var info:ImageInfo;
/**
* constructor
* @param imageInfo
*/
public function Image(imageInfo:ImageInfo)
{
this.info = imageInfo;
/*
* 文件加载类*/
_loader = new Loader();
/*_loader.contentLoaderInfo[只读] 返回与正在加载的对象相对应的LoaderInfo对象;*/
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
}
//-public method-//
/**
* 加载图像文件
*/
public function load():void{
var request:URLRequest = new URLRequest(AsciiArtBuilder.IMAGE_PATH+info.fileName);
_loader.load(request);
}
/**
* 获取位图BitmapData信息;
* @return
*/
public function getBitmapData():BitmapData{
return Bitmap(_loader.content).bitmapData;
}
//-Event Handling-//
/**
* 图像加载完成
* @param event
*/
private function onCompleteHandler(event:Event):void{
dispatchEvent(event);
}
}
}
=>BitmapToAsciiConverter.as
package com.cen.programmingas3.asciiArt
{
import flash.display.BitmapData;
/**
* 位图转换成字符图类
* about:Provides functionality(功能) for converting a bitmap image to an "ASCII Art" representation;
* @author cen
*/
public class BitmapToAsciiConverter
{
/**
* private vars*/
/*分辨率*/
private static const _resolution:Number = .025;
/*Bitmap 对象的数据(像素)*/
private var _data:BitmapData;
/*白色阀值*/
private var _whiteThreshold:Number;
/*黑色阀值*/
private var _blackThreshold:Number;
/*调色板
=>The characters in this string become increasingly(越来越) darker(深色);
=>This set of characters are the "grayscale(灰度) values" which are used to create the image;
=>There are 64 characters, meaning each character is used to represent four values in a common
256-value grayscale color palette (which has color values in the 0-255 range);
=>The characters are in order from darkest to lightest, so that their position (index)
in the string corresponds(对应) to a relative color value (with 0 = black).
*/
private static const palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. ";
/**
* constructor
* @param image
*/
public function BitmapToAsciiConverter(image:Image)
{
this._data = image.getBitmapData();
this._whiteThreshold = image.info.whiteThreshold;
this._blackThreshold = image.info.blackThreshold;
}
//-public method-//
/**
* 转换
* @about_Parses(解析) the bitmap data associated with(与…相联系) this instance and converts it to its "ASCII Art"
* (String) representation;
* @return string_The String representation of the bitmap image;
*/
public function parseBitmapData():String{
/*(red,green,blue)红绿蓝颜色表示法*/
var rgbVal:uint;
var redVal:uint;
var greenVal:uint;
var blueVal:uint;
/*灰色*/
var grayVal:uint;
var index:uint;
var verticalResolution:uint = Math.floor(_data.height * _resolution);
var horizontalResolution:uint = Math.floor(_data.width * _resolution * 0.45);
/*返回结果字符串*/
var result:String = "";
/**
* Loop through the rows of pixels top to bottom*/
for(var y:uint = 0; y<_data.height; y+=verticalResolution) {
/**
* loop through the left to right*/
for(var x:uint = 0; x<_data.width; x+=horizontalResolution) {
/**
* Extract(提取) individual(单个的) red, green, and blue values for the pixel*/
rgbVal = _data.getPixel(x,y);
redVal = (rgbVal & 0xFF0000) >> 16;
greenVal = (rgbVal & 0x00FF00) >> 8;
blueVal = rgbVal & 0x0000FF;
/**
* 灰度计算公式
* Calculate(计算) the gray value of the pixel:
* The formula(公式) for grayscale(灰度) conversion(转换): (Y = gray): Y = 0.3*R + 0.59*G + 0.11*B*/
grayVal = Math.floor(0.3*redVal + 0.59*greenVal + 0.11*blueVal);
/**
* 根据阀值确定灰度值:
* The white threshold and black threshold values (read from the "images.txt" file)
* determine the grayscale values that are the cut-off(界限) limits for white and black.
* Values outside the threshold will be "rounded" to pure(纯) white or black.*/
if(grayVal > _whiteThreshold) {
grayVal = 0xFF;
}else if(grayVal < _blackThreshold) {
grayVal = 0x00;
}else {
/**
* 灰度值居中时:
* Normalize(使标准化) the grayscale value along the relative scale between the white threshold
* and the black threshold. In other words(换句话说), adjust(调整) the palette so that
* the black threshold acts as the "0x00" value and the white threshold acts as the "0xFF(白)" value,*/
grayVal = Math.floor(0xFF * ((grayVal - _blackThreshold)/(_whiteThreshold - _blackThreshold)));
}
/**
* 获取此像素下标值:
* The value is now a gray value in the 0-255 range, which needs to be converted
* to a value in the 0-64 range (since that's the number of available "shades of gray*/
index = Math.floor(grayVal/4);
result += palette.charAt(index);
}
/*在行末添加换行符*/
result += "\n";
}
return result;
}
}
}
=>AsciiArtBuilder.as
package com.cen.programmingas3.asciiArt
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLLoader;
import flash.net.URLRequest;
import com.cen.programmingas3.asciiArt.ImageInfo;
import com.cen.programmingas3.asciiArt.Image;
import com.cen.programmingas3.asciiArt.BitmapToAsciiConverter;
/**
* 字符图(AsciiArt)创建类
* about:Provides application-level functionality for the AsciiArt sample;
* @author cen
*/
public class AsciiArtBuilder extends EventDispatcher
{
/**
* private vars*/
/*位图信息文本文件路径*/
private const DATA_TARGET:String = "public/txt/ImageData.txt";
/*位图信息文件加载器*/
private var _imageInfoLoader:URLLoader;
/*位图集数组*/
private var _imageStack:Array;
/*当前位图下标值*/
private var _currentImageIndex:uint;
/**
* public properties*/
/*存储位图文件夹路径*/
public static const IMAGE_PATH:String = "public/img/";
/*当前位图字符图字符串(初始化时为第一副位图)*/
public var asciiArtText:String = "";
/*获取当前位图*/
public function get currentImage():Image{
return _imageStack[_currentImageIndex];
}
/**
* constructor
*/
public function AsciiArtBuilder()
{
_imageStack = new Array;
/**
* 加载位图信息文本文件*/
var request:URLRequest = new URLRequest(DATA_TARGET);
_imageInfoLoader = new URLLoader();
_imageInfoLoader.addEventListener(Event.COMPLETE, onImageInfoCompleteHandler);
_imageInfoLoader.load(request);
}
//-Event Handlers-//
/**
* 位图信息文本文件加载完成后触发
* @param event
*/
private function onImageInfoCompleteHandler(event:Event):void{
/*将位图信息文本字符串转换成位图信息数组*/
var allImageInfo:Array = parseImageInfo();
/*创建位图*/
buildImageStack(allImageInfo);
}
private function onImageCompleteHandler(event:Event):void{
/*移动到第一副位图*/
next();
/**
* 分发“初始化加载位图”完成
* notify(通知) any listeners that the application has finished its initial loading*/
var readyEvent:Event = new Event("ready");
dispatchEvent(readyEvent);
}
//-method-//
/**
* 字符串首字母大写处理
* @param word
* @return
*/
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:
var firstLetter:String = word.substr(0,1);
firstLetter = firstLetter.toUpperCase();
var otherLetters:String = word.substring(1);
word = firstLetter + otherLetters;
}
return word;
}
/**
* 处理标题信息
* @param title
* @return
*/
private function normalizeTitle(title:String):String{
var words:Array = title.split(" ");
var len:uint = words.length;
for(var i:uint=0; i<len; i++) {
words[i] = capitalizeFirstLetter(words[i]);
}
return words.join(" ");
}
/**
* 解析位图信息文件_将位图信息文本字符串转换成位图信息数组;
* Each line of text contains info about one image, separated by tab (\t) characters;
* in this order:
* - file name
* - title
* - white threshold
* - black threshold
* Note that we skip the first line, since it only contains column headers.
* @return An Array of ImageInfo instances.
*/
private function parseImageInfo():Array{
var result:Array = new Array();
/*位图信息文件内容字符串*/
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];
/**
* 去除首尾的空白
* trim(修剪) leading(开头) or trailing(结尾) white space from the current line*/
imageInfoRaw = imageInfoRaw.replace(/^ *(.*) *$/, "$1");
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);//保存位图信息;
}
}
return result;
}
/**
* 创建位图数组
* @param imageInfo
*/
private function buildImageStack(imageInfo:Array):void{
/*位图*/
var image:Image;
/*位图信息*/
var oneImageInfo:ImageInfo;
/*监听器是否已经添加(初始化时只添加第一副位图监听器)*/
var listenerAdded:Boolean = false;
var numImages:uint = imageInfo.length;
for(var i:uint = 0; i<numImages; i++) {
_currentImageIndex = 0;
oneImageInfo = imageInfo[i];
image = new Image(oneImageInfo);
_imageStack.push(image);
if(!listenerAdded) {
image.addEventListener(Event.COMPLETE, onImageCompleteHandler);
listenerAdded = true;
}
image.load();
}
}
/**
* (完成)Advances the image stack to the next image, and populates the asciiArtText property
* with that image's ASCII Art representation.
*/
public function next():void{
_currentImageIndex++;
if(_currentImageIndex == _imageStack.length) {
_currentImageIndex = 0;
}
/**
* 获取位图字符图字符串*/
var imageConverter:BitmapToAsciiConverter = new BitmapToAsciiConverter(this.currentImage);
this.asciiArtText = imageConverter.parseBitmapData();
}
}
}
=>AsciiArtApp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
pageTitle="TheStudioOfCenyebao_AsciiArtDemo"
creationComplete="creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import com.cen.programmingas3.asciiArt.AsciiArtBuilder;
import com.cen.programmingas3.asciiArt.ImageInfo;
import mx.events.FlexEvent;
/*位图字符图创建变量*/
private var asciiArt:AsciiArtBuilder;
/**
* 页面创建完成
*/
protected function creationCompleteHandler(event:FlexEvent):void
{
asciiArt = new AsciiArtBuilder();
/**
* 监听初始化是否完成*/
asciiArt.addEventListener("ready", imageReady);
}
/**
* Called when the AsciiArtBuilder has loaded the image data and is ready to display an image.
*/
private function imageReady(event:Event):void{
updatePreview();
}
/**
* Updates the image preview display, including title and image, using the current image in the asciiArt object.
*/
private function updatePreview():void{
/*位图信息*/
var imageInfo:ImageInfo = asciiArt.currentImage.info;
/*位图显示*/
img.load(AsciiArtBuilder.IMAGE_PATH + imageInfo.fileName);
/*标题信息*/
sourceImage.title = imageInfo.title;
/*显示字符图*/
asciiArtText.text = asciiArt.asciiArtText;
}
/**
* 按钮单击事件
*/
private function onNextBtnClickHandler(event:MouseEvent):void{
/*跳到下一幅位图*/
asciiArt.next();
/*update the image preview*/
updatePreview();
}
]]>
</fx:Script>
<!--位图转换字符图示例-->
<s:HGroup verticalAlign="bottom"
horizontalCenter="0" verticalCenter="0">
<s:Panel id="sourceImage" height="100%"
backgroundColor="#b7babc" borderAlpha="1" borderColor="#666">
<s:VGroup width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
<mx:Image id="img" width="400" height="300"/>
</s:VGroup>
<s:controlBarContent>
<s:Spacer width="90%"/>
<s:Button id="nextBtn" buttonMode="true" useHandCursor="true"
label="NextImage" click="onNextBtnClickHandler(event)"/>
</s:controlBarContent>
</s:Panel>
<s:TextArea id="asciiArtText" fontSize="8" fontFamily="_typewriter"
width="550" height="450"/>
</s:HGroup>
</s:Application>