Png2fnt

From KBase

Jump to: navigation, search

Contents

[edit] Introduction

[edit] 기능

각종 tool 을 사용하여 글자를 그려 PNG 로 저장하면, 이것을 읽어 GFN 형식으로 저장한다. GFN 형식은 여기서 만든 형식이다.

[edit] 개발/실행 환경

  • Png2gpn 과 같다
    • cygwin - 기본적으로 cygwin 에서 build 하고 실행했지만, gd 가 동작하는 곳이라면 어디서나 가능하다.
    • gd - 최근 공식 사이트가 http://www.boutell.com/gd/ 에서 http://www.libgd.org/ 로 바뀌었다. Image 파일을 읽기 위해 사용한 라이브러리로, 현재 png 만 읽고 있다.

[edit] GFN file format

[edit] GFN file header

GFN 파일의 구조는 다음과 같다

 struct StFont {
   int signature;
   int version;
   unsigned short width;
   unsigned short height;
   unsigned short start_ch;
   unsigned short end_ch;
   int filesize;
   unsigned int data[1];
 };
signature 
이 file format 을 나타내기 위한 것으로 "gfnt" 가 들어간다.
version 
영문의 경우 0x01, 한글의 경우 0x03
width 
한 글자의 폭이 몇 pixel 인지
height 
한 글자의 높이가 몇 pixel 인지
start_ch 
첫 글자의 code. 영문의 경우 ascii 이며 한글 등의 경우 KSC-5601 을 사용한다
end_ch 
마지막 글자의 code
filesize 
파일 전체의 크기
data 
실제 data

[edit] GFN file body

  • pixel 당 4 bit 로 0 부터 8 까지의 alpha 값을 표현한다. 0 은 그려지지 않는 pixel 이고 8 은 온전히 그려지는 pixel 을 나타내며 그 사이의 값은 불투명도가 된다.
  • 세로 정보가 우선으로 저장된다. 즉, data 의 첫 번째 byte 는 (0,0) 과 (0,1) 위치의 pixel 값이다.
  • 세로줄 하나는 32bit 로 padding 된다. 즉 height 가 8의 배수가 아닐 경우 가장 가까운 8의 배수를 택해 pad_height 로 계산한다.
  • 글자 하나를 나타내기 위해 필요한 byte 수는 width * pad_height / 2 이다.
  • 파일 전체의 크기는 Header + (end_ch - start_ch + 1) * (width * pad_height / 2) 이다.

[edit] Read PNG Write GFN

  • PNG 파일은 24bit 형식이고 완전 투명한 배경 위에 Alpha 값을 가지는 pixel 로 글자를 써 넣어야 한다. pixel 의 color 는 상관하지 않는다
  • 현재는 Fixed width font 만 지원한다.
  • PNG 의 height 가 Font 의 height 가 되며 PNG 의 width 를 글자 수로 나눈 것이 font 의 width 가 된다.
  • 영문 폰트의 경우 0x20 부터 0x7F 까지를 한 line 에 모두 쓴 형태를 만들어 사용한다. start_ch 와 end_ch 는 -s 와 -e 옵션을 써서 변경할 수 있다.
  • 한글 폰트의 경우 완성형 배열을 그대로 사용한다. 즉 2350 자를 모두 표현하는 경우 0xB0A1 부터 0xC8FE 까지 중 valid 한 문자만 나열한 형태이다. 역시 옵션으로 변경 가능하다
  • 특히 한글 폰트의 경우 가로로 너무 길어 질 수가 있으므로 line 을 나누어 사용한다. 영문 폰트여도 가능하다.. 여러 라인에 나누어 쓰는 경우는 반드시 -l 옵션으로 줄 수를 지정해야 한다. default 옵션은 한글일 경우 2350 자를 한 줄에 94 자씩 25 라인에 나누어 쓰는 방식이다.

[edit] command line option

-h 
한글 폰트
-w16 
width 가 16 pixel 임을 나타낸다
-l25 
PNG 파일에 25 줄의 글자가 적혀 있음을 나타낸다. 지정하지 않을 경우 기본값은 25 이다
-s30 
시작 글자를 0x30 부터로 한다. 영문의 경우 0x20, 한글의 경우 0xB0A1 이 default 값이다.
-e39 
마지막 글자를 0x39 로 한다. 영문은 0x7F, 한글은 0xC8FE 가 default 값이다
-ty 
(미구현) y, Y 나 1 을 지정하면 transparency 로 판단하고 n 이나 0 을 지정하면 color 로 판단하게 하려고 했는데 구현하지는 않았다. 무조건 transparency 로 판단한다.
    switch (argv[i][1]) {
    case 'h':
        g_option.hangul = 1;
        break;
    case 'w':
        g_option.width = atoi(argv[i]+2);
        break;
    case 'l':
        g_option.line = atoi(argv[i]+2);
        break;
    case 's':
        num = hextoi(argv[i]+2);
        if (num >= 0) {
            g_option.start_ch = num;
        }
        break;
    case 'e':
        num = hextoi(argv[i]+2);
        if (num >= 0) {
            g_option.end_ch = num;
        }
        break;

[edit] Makefile

all: png2fnt.exe

png2fnt.exe: png2fnt.cpp
    g++ -o $@ $< -lgd

clean:
    rm png2fnt.exe

[edit] Drawing Font

[edit] Selecting Font

  • 사용하는 곳에서는 다음과 같이 쓴다
   Graphics *g = Graphics::getSingleton();
   g->setFont(Font::HYBDA_NUM_80);
   g->setColor(Color::BLACK);
   g->drawString(30, 20, szLine1);
  • struct StFont 는 영문, 한글 등 한 가지만 가지고 있으므로 Font class 는 struct StFont 를 여러 개 들고 있을 수 있도록 한다. 다음과 같은 mapping 을 사용한다. (소스 파일에서 의미 있는 부분만 남겨두었음)
    case LUCIDA_CONSOLE_24:
                (StFont *)lucida_console_24_gfn
    case HYBDA_NUM_80:
                (StFont *)hybda_number_80_gfn,
                (StFont *)malgun_18x22_gfn
    case MALGUN_18x22:
    default:
                (StFont *)lucida_console_24_gfn,
                (StFont *)malgun_18x22_gfn

[edit] Drawing Font

  • 그려야 할 곳의 x, y 로 Buffer pointer 를 얻는다
  • 그릴 char 를 골랐으면, Font 에게 data 를 묻는다. Font 는 자신이 가진 StFont 데이터 중 start_ch 와 end_ch 사이에 있는 것을 골라 data pointer 를 리턴한다.
  • Graphics::drawString 중
    for (; *str; str++) {
        unsigned short ch = (unsigned char)*str;
        if (ch & 0x80) {
            ch = (ch << 8) | (unsigned char)*++str;
        }
        int width, height;
        unsigned int *pData = pFont->getData(ch, &width, &height);
        if (!pData)
            continue;
  • Font::getData 중
unsigned int *Font::getData(unsigned short ch, int *width, int *height)
{
    StFont **fonts = m_pimpl->fonts;
    for (int i = 0; i < m_pimpl->count; i++, fonts++) {
        StFont *font = *fonts;
        if (ch < font->start_ch || font->end_ch < ch) {
             continue;
        }

        // 정보 채움
  • 받은 data 를 사용하여 pixel 을 변경한다. Png2gpn 에서 소개한 Alpha blending 기법을 사용하여 source color 와 destination pixel, font alpha value 를 조합한다
    int alpha = data & 0x0F;
    if (++shift_count >= 8) {
        shift_count = 0;
        data = *(++pData);
    } else {
        data >>= 4;
    }

    u32 dst = *curr;
    dst = (dst | (dst << 16)) & 0x3E07C1F;
    u32 result = ((color32 - dst) * alpha / 8 + dst) & 0x3E07C1F;
    *curr = result | (result >> 16) | BIT(15);
Personal tools
Wiki Help (mediawiki.org)