1、前言
這段時間的工做須要研究stb_truetype庫,所以本篇文章記錄一下該庫的基本用法。stb_truetype是一個常見字體加載庫, 只有一個頭文件, 功能雖沒有freetype庫強大,但代碼量小不少,在Flash很是小的開發板上也能夠用,以爲freetype庫太大的,建議使用stb_truetype庫。git
stb庫的GitHub倉庫:https://github.com/nothings/stb。github
2、stb_truetype解析ttf字體
使用stb_truetype庫解析ttf字體的步驟一般以下:ide
一、加載並初始化ttf字體文件;函數
二、設置字體大小(字號)並計算縮放比例;字體
三、獲取垂直方向上的度量並根據縮放比例調整,好比字高、行間距等;編碼
四、獲取水平方向上的度量,好比字寬、字間距等;url
五、獲取字符圖片的邊框(每一個字符轉化爲圖像的邊界);.net
六、調整每一個字體圖像的寬高(代碼中的x、y),並渲染字體;指針
至此,解析ttf字體已完成,附加步驟爲使用stb_image_write庫將渲染出來的圖像保存爲本地圖片,下面直接上代碼:code
注意:在包含stb_truetype.h頭文件的時候須要定義STB_TRUETYPE_IMPLEMENTATION,不然將會沒法使用。
#include <stdio.h> #include <stdlib.h> #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" /* http://nothings.org/stb/stb_image_write.h */ #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */ int main(int argc, const char *argv[]) { /* 加載字體(.ttf)文件 */ long int size = 0; unsigned char *fontBuffer = NULL; FILE *fontFile = fopen("font/default.ttf", "rb"); if (fontFile == NULL) { printf("Can not open font file!\n"); return 0; } fseek(fontFile, 0, SEEK_END); /* 設置文件指針到文件尾,基於文件尾偏移0字節 */ size = ftell(fontFile); /* 獲取文件大小(文件尾 - 文件頭 單位:字節) */ fseek(fontFile, 0, SEEK_SET); /* 從新設置文件指針到文件頭 */ fontBuffer = calloc(size, sizeof(unsigned char)); fread(fontBuffer, size, 1, fontFile); fclose(fontFile); /* 初始化字體 */ stbtt_fontinfo info; if (!stbtt_InitFont(&info, fontBuffer, 0)) { printf("stb init font failed\n"); } /* 建立位圖 */ int bitmap_w = 512; /* 位圖的寬 */ int bitmap_h = 128; /* 位圖的高 */ unsigned char *bitmap = calloc(bitmap_w * bitmap_h, sizeof(unsigned char)); /* "STB"的 unicode 編碼 */ char word[20] = {0x53, 0x54, 0x42}; /* 計算字體縮放 */ float pixels = 64.0; /* 字體大小(字號) */ float scale = stbtt_ScaleForPixelHeight(&info, pixels); /* scale = pixels / (ascent - descent) */ /** * 獲取垂直方向上的度量 * ascent:字體從基線到頂部的高度; * descent:基線到底部的高度,一般爲負值; * lineGap:兩個字體之間的間距; * 行間距爲:ascent - descent + lineGap。 */ int ascent = 0; int descent = 0; int lineGap = 0; stbtt_GetFontVMetrics(&info, &ascent, &descent, &lineGap); /* 根據縮放調整字高 */ ascent = roundf(ascent * scale); descent = roundf(descent * scale); int x = 0; /*位圖的x*/ /* 循環加載word中每一個字符 */ for (int i = 0; i < strlen(word); ++i) { /** * 獲取水平方向上的度量 * advanceWidth:字寬; * leftSideBearing:左側位置; */ int advanceWidth = 0; int leftSideBearing = 0; stbtt_GetCodepointHMetrics(&info, word[i], &advanceWidth, &leftSideBearing); /* 獲取字符的邊框(邊界) */ int c_x1, c_y1, c_x2, c_y2; stbtt_GetCodepointBitmapBox(&info, word[i], scale, scale, &c_x1, &c_y1, &c_x2, &c_y2); /* 計算位圖的y (不一樣字符的高度不一樣) */ int y = ascent + c_y1; /* 渲染字符 */ int byteOffset = x + roundf(leftSideBearing * scale) + (y * bitmap_w); stbtt_MakeCodepointBitmap(&info, bitmap + byteOffset, c_x2 - c_x1, c_y2 - c_y1, bitmap_w, scale, scale, word[i]); /* 調整x */ x += roundf(advanceWidth * scale); /* 調整字距 */ int kern; kern = stbtt_GetCodepointKernAdvance(&info, word[i], word[i + 1]); x += roundf(kern * scale); } /* 將位圖數據保存到1通道的png圖像中 */ stbi_write_png("STB.png", bitmap_w, bitmap_h, 1, bitmap, bitmap_w); free(fontBuffer); free(bitmap); return 0; }
運行後能夠見STB.png圖片,效果以下:
3、總結
以上即是stb_truetype庫的基本用法,能夠看出使用過程比較簡單,其中須要調整的參數主要是字體大小(字號),使用過程當中須要注意如下兩點:
一、上面已經提過,這裏再提一遍,在包含stb_truetype.h頭文件的時候須要定義STB_TRUETYPE_IMPLEMENTATION,不然將會沒法使用。
二、調用stb_truetype庫函數傳入的字符編碼必須是unicode編碼。