由於工作的需要,分配添加支持khmer,痛苦的煎熬了一個月,終於把它給整出來了,方便以後大家開發中提供一點點的幫助。
本次的開發主要採用開源的代碼來實現的。採用了兩種:harfbuzz跟freetype。
首先:介紹一下harfbuzz的基礎知識:
Harfbuzz 是一個開源的text opentype layout 引擎,它被應用於很多的開源項目中,如Pango,Filefox,Webkit,android等。
可以參考:http://my.oschina.net/wolfcs/blog/107635 ,文檔的介紹,我們就不必詳細的介紹了。
本次中主要是通過harfbuzz 獲取到glyph id,獲取到這個值。因時間比較緊張,暫時採用demo上的某些例子參考,並進行相應的修改。然後獲取到glyph id後,再通過freetype獲取到所需要字符的信息,其實獲取的這個字符image的信息,然後調用顯示的函數進行顯示出來。
代碼如下:
int GetKhmerStringInfo(int iLan, unsigned char *pucBuf, int iBufWidth, int iBufHeight, int iX, int iY, \
char *pcShowString, unsigned int uiFrontColor, int iXTimes, int iYTimes)
{
int iPenPos = 0;
int iFontMaxHeight = 0;
int iDrawHeight = 0;
unsigned int uiCount = 0;
unsigned int iLoop = 0;
const int FONT_MAX_SIZE = MaxFontSize();
int bError = 0;
hb_buffer_t *buffer;
hb_glyph_info_t *infos;
hb_glyph_position_t *positions;
hb_glyph_info_t *info;
hb_glyph_position_t *pos;
GS_TT_BITMAP stBitmap;
if (strlen(pcShowString) <= 0)
{
return -1;
}
iX = GetXPos(iX);
iY = GetYPos(iY);
iBufWidth = GetXPos(iBufWidth);
iBufHeight = GetYPos(iBufHeight);
iPenPos = iX;
GetttfFileData();
buffer = hb_buffer_create();
hb_buffer_add_utf8(buffer, (const char *)pcShowString, -1, 0, -1);
hb_buffer_guess_segment_properties(buffer);
hb_shape(font, buffer, NULL, 0);
uiCount = hb_buffer_get_length(buffer);
infos = hb_buffer_get_glyph_infos(buffer, NULL);
positions = hb_buffer_get_glyph_positions(buffer, NULL);
stBitmap.pucBuffer = GSOS_Malloc(FONT_MAX_SIZE);
if (NULL == stBitmap.pucBuffer)
{
return 0;
}
for (iLoop = 0; iLoop < uiCount; iLoop++)
{
info = &infos[iLoop];
pos = &positions[iLoop];
bError = FT_Load_Glyph(stFTFace, info->codepoint, FT_LOAD_DEFAULT);
if (stFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
{
bError = FT_Render_Glyph(stFTFace->glyph, FT_RENDER_MODE_NORMAL);
}
memset (stBitmap.pucBuffer, 0, FONT_MAX_SIZE);
RenderGlyphInternal(&(stFTFace->glyph->outline), &stBitmap);
if (iPenPos == iX && stBitmap.iLeft < 0)
{
stBitmap.iLeft = 0;
}
#if HD_OSD || OSD_NAME == SUPER
iDrawHeight = GetYPos(28 - iFontMaxHeight)/2;
#endif
DrawFontBitmap(pucBuf, iBufWidth, iBufHeight, iPenPos + stBitmap.iLeft, \
iY+4 - stBitmap.iTop + iDrawHeight, &stBitmap, uiFrontColor);
iPenPos += (stFTFace->glyph->metrics.horiAdvance >> 6)*iXTimes;
}
hb_buffer_destroy(buffer);
GSOS_Free(stBitmap.pucBuffer);
return GetHD2SDXPos(iPenPos - iX);
}
因爲freetype需要每次傳入一個字符進入索引到對應的圖形,獲取到字符的等信息,因每次都需要malloc or read or create,使用一個全局的變量控制。
。
int GetttfFileData(void)
{
if (iOpenFileOnlyOnce > 0)
{
iOpenFileOnlyOnce--;
FILE *fpttf;
hb_blob_t *blob = NULL;
hb_destroy_func_t destroy;
unsigned int upem = 0;
void *user_data = NULL;
char *font_data = NULL;
hb_memory_mode_t mm = HB_MEMORY_MODE_WRITABLE;
fpttf = fopen(TTF_SAVE_FALSH_PATCH, "rb");
if (NULL == fpttf)
{
printf("open ttf file faild!, [%s, %d]\r\n", __FUNCTION__, __LINE__);
return 0;
}
fseek(fpttf, 0, SEEK_END);
uifpLen = ftell(fpttf);
fseek(fpttf, 0, SEEK_SET);
if (NULL != font_data)
{
GSOS_Free(font_data);
font_data = NULL;
}
font_data = GSOS_Malloc(uifpLen);
uifpLen = fread(font_data, 1, uifpLen, fpttf);
fclose(fpttf);
user_data = (void *)font_data;
blob = hb_blob_create((const char *)font_data, uifpLen, mm, user_data, destroy);
face = hb_face_create(blob, 0);
hb_blob_destroy(blob);
blob = NULL;
upem = hb_face_get_upem(face);
font = hb_font_create(face);
hb_font_set_scale(font, upem, upem);
hb_ft_font_set_funcs(font);
GetFreetypeFace(TTF_SAVE_FALSH_PATCH, KHMER_FONT_SIZE, &stFTFace);
}
return uifpLen;
}
當切換到其他的語言時,就可以free掉了。
void FreeHarfbuzzMem(void)
{
if (NULL != font)
{
hb_font_destroy(font);
font = NULL;
}
if (face)
{
hb_face_destroy(face);
face = NULL;
}
iOpenFileOnlyOnce = 1;
}
以下就是初始化freetype
static int GetFreetypeFace(char *ttf, int font_size, FT_Face *face)
{
FT_Library library;
if (font_size < 1 || font_size > 72)
{
return -1;
}
if (FT_Init_FreeType(&library) != 0)
{
return -2;
}
if (FT_New_Face(library, ttf, 0, face) != 0)
{
return -3;
}
FT_Set_Char_Size(*face, 0, font_size * 64, 96, 96);
return 0;
}
至於一些定義,我就不提供了,可以參考其他,至於修改的lib後期再共享一下。