スポンサーリンク
カーニングはアルファベットを描画する際に例えばVとAの間を狭く描画するような描画位置調整のことで、GT_Get_Kerningで文字の位置の差を取得する。
#include <iostream> #include <vector> #include <ft2build.h> #include FT_FREETYPE_H #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib") void pnmP2_Write( const char* const fname, const int width, const int height, const unsigned char* const p); void draw( const int width, const int height, unsigned char* p, const int charw, const int charh, const int ox, const int oy, const unsigned char* charp ); int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\meiryo.ttc", 0, &face ); //文字コード指定 error = FT_Select_Charmap( face, // target face object FT_ENCODING_UNICODE // エンコード指定 ); if (error == FT_Err_Unknown_File_Format) return -1; else if (error) return -1; //この二つの値でフォントサイズ調整 FT_F26Dot6 fontsize = 32 * 64; FT_UInt CHAR_RESOLUTION = 300; error = FT_Set_Char_Size( face, // handle to face object 0, // char_width in 1/64th of points fontsize, // char_height in 1/64th of points CHAR_RESOLUTION, // horizontal device resolution CHAR_RESOLUTION); // vertical device resolution // 出力画像のメモリ確保 const int iw = 500; const int ih = 300; std::vector<unsigned char> image(iw*ih,0);
// カーニングのために直前の文字を保存しておく FT_UInt previous_glyph = 0;
// 描画位置 int posx = 0; int posy = 200; for (size_t i = 0; i < 4; i++) { // 文字の取得 FT_ULong character = U"VAOX"[i]; FT_UInt char_index = FT_Get_Char_Index(face, character);
// カーニング
if(previous_glyph && true/*カーニングしないならfalse*/) { FT_Vector kerning_delta; // 文字のずれ量を保存 // 文字のシフト量を取得 FT_Get_Kerning( face, previous_glyph, char_index, FT_KERNING_DEFAULT, &kerning_delta ); posx += ( kerning_delta.x >> 6 );// 文字のシフト } // 直前に使ったグリフを更新 previous_glyph = char_index;
// グリフ(字の形状)読込
error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER);
if (error)
return -1; // ignore errors
// 文字を画像化
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
// 出力画像に文字を書き込み
draw(
//出力先データ
iw, ih, image.data(),
// 文字の画像
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
posx + face->glyph->bitmap_left,
posy - face->glyph->bitmap_top,
face->glyph->bitmap.buffer
);
posx += (face->glyph->advance.x >> 6);
posy -= (face->glyph->advance.y >> 6);
}
pnmP2_Write(// ファイル保存
"C:\\MyData\\freetypetest.pgm",
iw,
ih,
image.data()
);
// FreeType2の解放
FT_Done_Face(face);
FT_Done_FreeType(library);
}
//! @brief Portable Gray map
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void pnmP2_Write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p) { // PPM ASCII
FILE* fp = fopen(fname, "wb");
fprintf(fp, "P2\n%d %d\n%d\n", width, height, 255);
size_t k = 0;
for (size_t i = 0; i < (size_t)height; i++) {
for (size_t j = 0; j < (size_t)width; j++) {
fprintf(fp, "%d ", p[k]);
k++;
}
fprintf(fp, "\n");
}
fclose(fp);
}
//! @brief 出力画像へ文字を書き込む
//! @param [in] width 出力先のサイズ
//! @param [in] height 出力先のサイズ
//! @param [out] p 出力先
//! @param [in] charw 文字画像のサイズ
//! @param [in] charh 文字画像のサイズ
//! @param [in] ox 描画始点
//! @param [in] oy 描画始点
//! @param [in] charp 文字画像
void draw(
const int width,
const int height,
unsigned char* p,
const int charw,
const int charh,
const int ox,
const int oy,
const unsigned char* charp
) {
for (int cx = 0; cx < charw; cx++) {
for (int cy = 0; cy < charh; cy++) {
int x = ox + cx;
int y = oy + cy;
if (x < 0 || x >= width)continue;
if (y < 0 || y >= height)continue;
int ipos = y * width + x;
int cpos = cy * charw + cx;
int c = (int)(p[ipos]) + (int)(charp[cpos]);
c = std::min(c, 255);
p[ipos] = c;
}
}
}