Korean Font Rendering
From WhiteWing
Jump to: navigation, search

WordPress has the most well-designed blog skins. There is an interesting feature, if you see its web page throughly, that all of the subjects of the postings are actually images. I guess this is same technology as MediaWiki-math package has: you render the font inside the server, make it as an image file, and upload it instead of the text. Two advantages arise: 1) you can use the fonts that the clients do not have, and 2) you don't have to rely on the horrible font rendering of the web browsers. 1) is actually very very important especially for Korean web sites, because there are a few Korean basic fonts.

My goal is to build a TextCube plugin. This small project is composed of four steps: 1) searching a good Korean type which is open to everybody, 2) finding a good font renderer, 3) making a simple program that generates the image with the given font, text, and several variables, and 4) building the TextCube plugin using this program.

Contents

Image Library

  • CImg : 역시 transparency 없음.
  • pngwriter : 이 병신같은 라이브러리는 png 전용으로 만들어졌으면서 transparency는 지원하지도 않는다.
  • libpng

Result

잠 못 이루는 Seattle의 밤...
Image:chosunilbo_font.png : Chosunilbo Myeongjo
Image:baekmuk_batang_font.png : Baekmuk Batang
Image:yoon_batang_font.png : Yoon Design Batang

Korean Fonts : 한글 명조 서체 배포판

사실 웹페이지의 글씨가 후진 것은 브라우저의 후진 렌더링 때문인 것이기에, 포토샵에서 불러서 비교하여 보았다. 22pt 사이즈 정도로 읽어들였으며, 글씨체가 큰 편이기에 자간을 줄여서 보았다. 우선 폰트 공작소에서 무료 배포판 서체들을 구할 수 있는 곳을 잘 정리해 놓았으며, 여기서 많은 도움을 받았음을 밝힌다. 아, 또 쓸만한 폰트 뷰어는 Nexus Font Viewer라는 것이 있는데, 윈도우즈 상에 서체를 인스톨 하지 않아도 대충 뭐가 어떻게 보이는지 알기 편하다.

  • 바탕 : 윈도우즈에 기본으로 깔려 있는 폰트. 물론 배포판은 아니긴 한데, 이것과 너무 비슷한 폰트를 골라 버리면 오히려 사소한 폰트 선정 오류로 보일 수 있을 것이다.
  • 조선일보 명조체 : 21M의 압박. 영문/숫자가 좀 수수하지만 봐 줄만 하다.
  • 윤디자인 웹바탕체 : 이것도 역시 보기 좋다.
  • 한겨레 결체 : 제목으로 하기에는 많이 부족하다.
  • 백묵 바탕체 : 리눅스 배포판인 백묵 폰트. 백묵 바탕은 굳이 렌더링 하지 않아도 리눅스 파이어폭스에서 꽤나 괜찮게 보인다. 그나저나 홈페이지 디자인은 왜 이렇게 구린지. 백묵폰트는 저 홈페이지에서는 받을 수 없고 KLDP.net[1]에서 다운받을 수 있다.
  • 한글글꼴개발원 : 뭐하는 곳인지 모르겠다. 글꼴에 영어/숫자도 포함되어 있지 않다.
  • 사실 어도비 명조가 제일 맘에 들긴 한데, 배포판이 아니다.

FreeType

There is a nice font rendering open source program called FreeType - I think that site has one of the most fanciest image among source project web sites.

Here is a sample program that reads fonts and builds an image. To run this program, you should include CImg Library. Also, you should handle unicode case, and I got the base code from romantica[2].

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "CImg.h"
using namespace cimg_library;
 
#define WIDTH 800
#define HEIGHT 800
 
unsigned char image[HEIGHT][WIDTH];
 
void
draw_bitmap( FT_Bitmap* bitmap,
FT_Int x,
FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
 
for ( i = x, p = 0; i < x_max; i++, p++ )
{
for ( j = y, q = 0; j < y_max; j++, q++ )
{
if ( i >= WIDTH || j >= HEIGHT )
continue;
 
image[i][j] |= bitmap->buffer[q * bitmap->width + p];
}
}
}
 
 
void
show_image( void )
{
int i, j;
CImg<unsigned char> img(HEIGHT, WIDTH, 1, 3, 0);
for ( i = 0; i < HEIGHT; i++ ) {
for ( j = 0; j < WIDTH; j++ ) {
const unsigned char color[] = {255-image[i][j], 255-image[i][j], 255-image[i][j]};
img.draw_point(i, j, color);
}
}
img.save("temp.bmp");
}
 
const char utf8_skip[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
 
static inline unsigned int utf8_get_char (char *p)
{
unsigned int result;
unsigned char c = *p;
int i, len;
 
if (!(c & 0x80))
return (unsigned int) c;
 
if (c > 0xfd)
return (unsigned int) -1;
 
len = utf8_skip[c];
 
result = p[0] & (0x7c >> len);
 
for (i = 1; i < len; i++) {
 
if ((p[i] & 0xc0) != 0x80)
return (unsigned int) -1;
 
result <<= 6;
result |= p[i] & 0x3f;
}
 
return result;
}
 
 
 
int main( int argc, char** argv )
{
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_UInt glyph_index;
FT_Vector pen;
FT_Error error;
 
char* filename;
char* text;
 
int target_height;
int num_chars;
 
int *steps;
unsigned int *chars;
 
if ( argc != 3 )
{
fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );
exit( 1 );
}
 
filename = argv[1];
text = argv[2];
num_chars = strlen( text );
target_height = HEIGHT - 200;
 
error = FT_Init_FreeType( &library );
error = FT_New_Face( library, argv[1], 0, &face );
error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
error = FT_Set_Char_Size( face, 50 * 64, 0, 100, 0 );
 
slot = face->glyph;
pen.x = 0;
pen.y = 100 * 64;
 
chars = (unsigned int *)calloc(sizeof(unsigned int), num_chars);
if (!chars)
return 1;
steps = (int*)calloc(sizeof(int), num_chars);
if (!steps) {
free(chars);
return 1;
}
 
int offset;
FT_Bool use_kerning;
FT_UInt previous;
 
use_kerning = FT_HAS_KERNING( face );
previous = 0;
 
for (offset=0; offset<num_chars; offset+=steps[offset]) {
steps[offset] = utf8_skip[(unsigned char)text[offset]];
chars[offset] = utf8_get_char(&text[offset]);
glyph_index = FT_Get_Char_Index(face, chars[offset]);
 
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
error = FT_Get_Kerning( face, previous, glyph_index, FT_KERNING_DEFAULT, &delta );
pen.x += delta.x >> 6;
}
 
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
 
draw_bitmap( &slot->bitmap,
pen.x + slot->bitmap_left,
target_height - slot->bitmap_top );
 
pen.x += slot->advance.x >> 6;
pen.y += slot->advance.y >> 6;
previous = glyph_index;
}
 
show_image();
 
FT_Done_Face ( face );
FT_Done_FreeType( library );
 
return 0;
}

References

  1. kldp.net, http://kldp.net/projects/baekmuk/
  2. romantica: the referred page is removed from the web site, so I just link a cached history from google. I'm not sure it will still work in the future [1].
.
Powered by MediaWiki. Designed by BlueBrown.