July 22, 2008

透過 FreeType 繪製 Unicode ASCII Art

在 hellwolf 那邊讀到有趣的文章 [玩具 : 用 freetype2 顯示 ascii-art 中文],給了範例程式碼,以 FreeType 2 的 API 描繪 glyph (字元對應的字型字體資料),所以只要知曉 Unicode 的索引值,就可輕鬆描繪字體外觀,不失為簡潔明暸的入門。

筆者將原本的程式碼簡化並標注彩色輸出,可參考 [ftart.c]:
/* Taken from http://blog.chinaunix.net/u/8057/showart_335549.html
 * with slight modifications */
#include <ft2build.h>
#include FT_FREETYPE_H
#include <strings.h>

int main(int argc, char **argv)
{
	int psize;
	FT_Library library;
	FT_Face face;
	unsigned int ucode;
	FT_UInt glyph_index;
	int row, pixel;
	char *fp;

	if (argc != 4) {
		return 10;
	}

	ucode = strtol(argv[2], NULL, 16);
	psize = strtol(argv[3], NULL, 10);

	printf("unicode +%X size %d \n", ucode, psize);
	printf("font %s\n", (fp = rindex(argv[1], '/')) != NULL ?
	             fp  + 1 : argv[1]);
	if (FT_Init_FreeType(&library) ||
	    FT_New_Face(library, argv[1], 0, &face) ||
	    FT_Set_Pixel_Sizes(face, psize, 0)) {
		return 1;
	}

	glyph_index = FT_Get_Char_Index(face, ucode);
	if (glyph_index == 0) {
		return 2;
	}
	if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)) {
		return 3;
	}
	if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO)) {
		return 4;
	}

	/* FIXME: we shall reserve space for low length
	 * (face->glyph->bitmap.rows - face->glyph->bitmap_top)
	 */
	for (row = 0; row < face->glyph->bitmap.rows; ++row) {
		for (pixel = 0; pixel < face->glyph->bitmap_left; ++pixel)
			printf("_");
		for (pixel = 0; pixel < face->glyph->bitmap.width; ++pixel){
			if (face->glyph->bitmap.buffer
					[row * face->glyph->bitmap.pitch +
					 pixel / 8] & (0xC0 >> (pixel % 8)))
				printf("\033[44;37m" " " "\033[m");
			else
				printf("_");
		}
		printf("\n");
	}
	return 0;
}
由上,我們可發現以下六個 FreeType API,對應的描述如下:
  • FT_Init_FreeType : 初始化 FreeType library 物件
  • FT_New_Face : 呼叫 FT_Open_Face 開啟指定路徑的字型,建立 face 物件
  • FT_Set_Pixel_Sizes : 呼叫 FT_Request_Size 以索取象徵性 (可能與實際描繪有出入) 的字型大小,單位 pixel
  • FT_Get_Char_Index : 傳回給定字元碼的 glyph,本函數使用 charmap 物件去進行編碼的映射
  • FT_Load_Glyph : 載入單一 glyph 資料到 face 物件中
  • FT_Render_Glyph : 轉換給定的 glyph 圖形為點陣圖
再回頭看程式碼,就很清楚了,根據給定的 Unicode 索引值去找到指定字型檔裡頭的 glyph,然後建立 FreeType 的 face 物件,並將找到的 glyph 指定並要求描繪出來,依據輸出的點陣圖,透過 ASCII 符號輸出。為了簡化程式設計,這裡僅用兩種字元來作區隔。

編譯方式如下:
$ gcc `pkg-config freetype2 --cflags --libs` -o ftart ftart.c -Wall
執行時,需給定三個參數,分別為 TrueType 字型檔名、Unicode 索引值,與期望的點數 (ASCII 的行列數量),以小弟的名裡頭的「群」為例,可依以下方式執行:
$ ./ftart \
    /usr/share/fonts/truetype/arphic/uming.ttc \
    `echo -n "群" | iconv -t ucs2 | od -tx1 | head -n1 | awk '{print $3$2}'` \
    24
這邊用了 shell script 的「魔法」,透過 iconv 取得 UCS2 編碼的表示值,倘若分別用 [CJKUnifonts] 與 [文泉驛] 帶入,可得類似以下輸出:

環肥燕瘦,各有姿色 :-)
由 jserv 發表於 July 22, 2008 12:25 PM
迴響

好神啊!! 這麼說來,其實連 Xft 都可以不用了?
直接用這個惡搞,動點手腳,就可以在 X 程式裡面輸出這些 pixels?

PCMan 發表於 July 22, 2008 03:46 PM

Xft 幫我們處理好, 直接用 X Rendering Extension 畫上去,何苦自己再重做一次。除非你只是好玩!

Thinker 發表於 July 22, 2008 05:24 PM
發表迴響









記住我的資訊?