Png2fnt
From KBase
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);

