title: freetype 字形解析
date: 2019/3/7 20:17:46
toc: true
freetype 字形解析
字體管理
管理字形,這里可以拆分為兩個部分,一部分為管理字距,一部分為有效數據(位圖信息).
比如字母g,藍色框里的是有效的位圖信息,但是排版的時候,是需要考慮字距的,否則雖然不重疊,但是不太好看.
數據結構
這里記住一個點
我們一般都是先轉換到字符到字形槽,然后從字形槽提取位圖,提取邊界bbox
https://www.freetype.org/freetype2/docs/reference/ft2-index.html
這里有兩個結構去描述
位圖描述
typedef struct FT_Bitmap_
{
unsigned int rows;
unsigned int width;
int pitch;
unsigned char* buffer;
unsigned short num_grays;
unsigned char pixel_mode;
unsigned char palette_mode;
void* palette;
} FT_Bitmap;
位圖的定位點描述在字形槽里
//字形槽
typedef struct FT_GlyphSlotRec_
{
FT_Library library;
FT_Face face;
FT_GlyphSlot next;
FT_UInt reserved; /* retained for binary compatibility */
FT_Generic generic;
FT_Glyph_Metrics metrics;
FT_Fixed linearHoriAdvance;
FT_Fixed linearVertAdvance;
FT_Vector advance; //下個邊界的原點
FT_Glyph_Format format;
FT_Bitmap bitmap; //位圖的描述
FT_Int bitmap_left; //位圖的左上角點
FT_Int bitmap_top; //位圖的左上角點
FT_Outline outline;
FT_UInt num_subglyphs;
FT_SubGlyph subglyphs;
void* control_data;
long control_len;
FT_Pos lsb_delta;
FT_Pos rsb_delta;
void* other;
FT_Slot_Internal internal;
} FT_GlyphSlotRec;
位置的邊界需要去手動獲取
這里的參數是FT_Glyph glyph
,可以由face
中的槽來轉換
//從face的字形槽中取得字形
//FT_EXPORT( FT_Error )FT_Get_Glyph( FT_GlyphSlot slot,FT_Glyph *aglyph );
//字形描述
typedef struct FT_GlyphRec_
{
FT_Library library;
const FT_Glyph_Class* clazz;
FT_Glyph_Format format;
FT_Vector advance;
} FT_GlyphRec;
error = FT_Get_Glyph( face->glyph, &glyph );
//從字形中取得bbox邊界
FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
FT_EXPORT( void )
FT_Glyph_Get_CBox( FT_Glyph glyph,
FT_UInt bbox_mode,
FT_BBox *acbox );
//傳入參數
typedef struct FT_GlyphRec_
{
FT_Library library;
const FT_Glyph_Class* clazz;
FT_Glyph_Format format;
FT_Vector advance;
} FT_GlyphRec;
// 傳出參數
typedef struct FT_BBox_
{
FT_Pos xMin, yMin;
FT_Pos xMax, yMax;
} FT_BBox;
字體抽象
剛開始我想抽象出位圖信息
長
寬
每個像素的bpp
換行像素位置
位圖數據地址
那么除非我自己去控制字距,同時需要統計這一行的高度,來確定下一行文字的位置,但是這可能會排版成擁擠的上對齊,或者手動計算位圖的大小,去布局,比如先設計一個32*32的邊界,然后根據這個位圖的大小居中擺放…想想就麻煩,而且這樣的話設計字體旋轉就沒轍了
再仔細看下freetype的布局,其實是創建了一個布局,接着再看下旋轉,我們實際刷新數據的時候,一般還是從左到右,從上到下刷新點,沒有顏色的數據應該不去刷新,我們看下之前的字體旋轉,可以發現是遮擋了的,所以遇到沒有顏色的數據,應該去跳過這些點,而不是去繪圖.
藍色框是點陣圖,我們刷新像素的位置
紅色框是邊界,用來描述布局的
我們之前的繪圖是這樣的
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 < 0 || j < 0 ||
i >= var.xres || j >= var.yres )
continue;
// 添加下面這句話即可
// if(bitmap->buffer[q * bitmap->width + p])
lcd_put_pixel(i,j,bitmap->buffer[q * bitmap->width + p]);
}
}
}
這里對所有點都進行重繪,所以理論上應該會有字符的遮蓋,上一節的實驗也確實如此,可以看到h會把a遮擋了
修改下代碼,判斷如果沒有顏色,則不需要描點即可,這里可以設置freetype的bpp是1即可,具體字體的顏色另外繪圖指定即可.