문자열 예제: ASCII Art

Flash Player 9 이상, Adobe AIR 1.0 이상

ASCII Art 예제에서는 ActionScript 3.0에서 String 클래스를 사용한 작업의 다양한 기능을 보여 줍니다. 다음은 그 기능 중 일부입니다.

  • String 클래스의 split() 메서드는 문자 구분 문자열에서 값을 추출(탭 구분 텍스트 파일의 이미지 정보)하는 데 사용됩니다.

  • split() , 연결 및 substring() , substr() 을 사용한 문자열 일부 추출 등을 비롯한 여러 문자열 조작 기술은 이미지 제목에서 각 단어의 첫 번째 글자를 대문자화하는 데 사용됩니다.

  • getCharAt() 메서드는 문자열에서 단일 문자를 가져오는 데 사용됩니다(회색 음영 비트맵 값에 해당하는 ASCII 문자를 확인하는 데 사용).

  • 문자열 연결은 한 번에 하나의 문자씩 이미지의 ASCII Art 표현을 작성하는 데 사용됩니다.

ASCII Art 는 Courier New 문자와 같은 고정폭 글꼴 문자로 구성된 격자를 사용하여 이미지를 표시하는 것으로, 이미지를 텍스트로 표현한 것을 나타냅니다. 다음 이미지는 응용 프로그램에서 생성된 ASCII Art의 예입니다.

ASCII Art - 텍스트 문자로 렌더링된 이미지
오른쪽 이미지는 그래픽의 ASCII Art 버전입니다.

이 샘플에 대한 응용 프로그램 파일을 가져오려면 www.adobe.com/go/learn_programmingAS3samples_flash_kr 을 참조하십시오. ASCIIArt 응용 프로그램 파일은 Samples/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

제목, 이미지 파일 URL 등과 같은 ASCII Art 이미지에 대한 메타데이터를 나타내는 클래스입니다.

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

이 파일은 특정 탭 구분 포맷을 사용합니다. 첫 번째 줄(행)은 머리글 행입니다. 나머지 행에는 로드할 각 비트맵에 대한 다음 데이터가 포함됩니다.

  • 비트맵의 파일 이름

  • 비트맵의 표시 이름

  • 비트맵의 흰색 임계값 및 검정 임계값. 16진수 값으로 이 값 위 및 아래의 픽셀은 완전한 흰색이나 완전한 검정으로 간주됩니다.

응용 프로그램이 시작되면 즉시 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) 
    { 
        // 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); 
    } 
}

텍스트 파일의 전체 내용은 단일 문자열 인스턴스인 _imageInfoLoader.data 속성에 포함됩니다. 개행 문자( "\n" )를 매개 변수로 한 split() 메서드를 사용하여, 문자열 인스턴스를 각 요소가 텍스트 파일의 개별 행인 배열( 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() 메서드는 각 단어의 첫 번째 글자를 대문자로 바꾸는 작업을 합니다.

    /** 
     * 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 Art 텍스트 생성

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;

이 코드는 비트맵 이미지의 ASCII Art 버전을 작성하는 데 사용될 result 라는 문자열 인스턴스를 먼저 정의합니다. 그런 다음 소스 비트맵 이미지의 개별 픽셀에 대해 작업을 반복합니다. 즉, 여러 색상 조작 기술을 사용하여(지면 관계상 자세한 내용은 생략) 개별 픽셀의 빨강, 녹색, 파랑 색상 값을 단일 회색 음영 값(0-255)으로 변환합니다. 그런 다음 위의 코드와 같이 이 값을 4로 나누어 0-63 사이의 값으로 변환한 후, 변수 index 에 저장합니다. 이 응용 프로그램에서 사용되는 사용 가능한 ASCII 문자 "팔레트"에 64개의 값이 포함되므로 0-63 사이의 값이 사용됩니다. 문자의 팔레트는 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 문자를 정의하므로, 문자는 charAt() 메서드를 사용하여 palette String에서 가져옵니다. 그런 다음 이 문자를 연결 대입 연산자( += )를 사용하여 result 문자열 인스턴스에 추가합니다. 또한 각 픽셀 행의 끝에서, 개행 문자를 result String의 끝에 연결하여 새 문자 "픽셀" 행을 줄을 바꿔 표시하도록 합니다.