True type fontをbitmapにレンダリングするプログラムを作成しました。レンダリングにはFreeTypeライブラリを使用しました。プログラムの作成はRaspberry Pi4で行っています。画像の表示にはEGGX / ProCALLライブラリを使用しました。
複数行の表示と角度を指定して表示できるようにしました。
アンチエリアシングあり
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <eggx.h> /* EGGX を使う時に必要 */
int strwlen(char *buf)
{
// LC_CTYPE をネイティブロケールに変更
if (setlocale(LC_CTYPE, "") == NULL)
{
fprintf(stderr, "do not set locale.\n");
exit(EXIT_FAILURE);
}
int i = 0;
int count = 0;
while (buf[i] != '\0')
{
int res = mblen(&buf[i], MB_CUR_MAX);
if (res < 0)
{
fprintf(stderr, "Contains illegal characters.\n");
exit(EXIT_FAILURE);
}
i += res;
count++;
}
return count;
}
#define SIZE_OF_ARRAY(array) (sizeof(array) / sizeof(array[0]))
int main(int argc, char *argv[])
{
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
int error, win;
char text[] = "hello,world!\nこんにちは世界\nrotation\n回転";
wchar_t ws[256]; /* ワイド文字保存用 */
int num_chars = strwlen(text);
int draw_x = 100; /* 表示座標 x */
int draw_y = 200; /* 表示座標 y */
int len = mbstowcs(ws, text, SIZE_OF_ARRAY(ws));
if (len == -1)
{
fprintf(stderr, "mbstowcs error\n");
exit(EXIT_FAILURE);
}
gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
win = gopen(500, 400); /* 1000x600 ピクセルのグラフィックス用ウィンドゥを開く */
layer(win, 0, 1); /* 描画レイヤを設定 */
// FreeTypeの初期化とTrueTypeフォントの読み込み
error = FT_Init_FreeType(&library);
if (error)
{
fprintf(stderr, "error FT_Init_FreeType\n");
exit(EXIT_FAILURE);
}
error = FT_New_Face(library, "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", 0, &face);
if (error == FT_Err_Unknown_File_Format)
{
fprintf(stderr, "unsupport fonts format\n");
exit(EXIT_FAILURE);
}
else if (error)
{
fprintf(stderr, "fonts file not found\n");
exit(EXIT_FAILURE);
}
slot = face->glyph;
error = FT_Set_Pixel_Sizes(face, 0, 60); //ピクセル単位でサイズ指定
//error = FT_Set_Char_Size( face, 0, 16 * 64, 300, 300); //ポイント単位でサイズ指定
if (error)
{
fprintf(stderr, "FT_Set_Pixel_Sizes\n");
exit(EXIT_FAILURE);
}
FT_Matrix matrix; /* transformation matrix */
double angle = M_PI / 4.0; /* 回転角度 */
FT_Vector pen; /* untransformed origin */
int line = 0;
/* set up matrix */
matrix.xx = (FT_Fixed)(cos(angle) * 0x10000L);
matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L);
matrix.yx = (FT_Fixed)(sin(angle) * 0x10000L);
matrix.yy = (FT_Fixed)(cos(angle) * 0x10000L);
pen.x = draw_x * 64;
pen.y = (-draw_y) * 64;
for (int n = 0; n < num_chars; n++)
{
int i;
FT_Bitmap bitmap;
FT_Set_Transform(face, &matrix, &pen);
switch (ws[n])
{
case '\r':
pen.x = draw_x * 64 + cos(angle - M_PI / 2) * line * (face->size->metrics.height);
pen.y = -draw_y * 64 + sin(angle - M_PI / 2) * line * (face->size->metrics.height);
break;
case '\t': /*tabは正しく計算していません */
pen.x = pen.x - sin(angle - M_PI / 2) * (face->size->metrics.max_advance);
pen.y = pen.y + cos(angle - M_PI / 2) * (face->size->metrics.max_advance);
break;
case '\n':
line++;
pen.x = draw_x * 64 + cos(angle - M_PI / 2) * line * (face->size->metrics.height);
pen.y = -draw_y * 64 + sin(angle - M_PI / 2) * line * (face->size->metrics.height);
//(face->size->metrics.height>>6) 1文字の最大高さ 次の行のベースライン 固定小数点 26.6 bit
break;
default:
// n文字目の文字をビットマップ化
error = FT_Load_Char(face, ws[n], FT_LOAD_RENDER); // 横書き
if (error)
{
fprintf(stderr, "FT_Load_Char error\n");
exit(EXIT_FAILURE);
}
bitmap = slot->bitmap;
for (i = 0; i < bitmap.rows * bitmap.width; i++)
{
newrgbcolor(win, bitmap.buffer[i], bitmap.buffer[i], bitmap.buffer[i]);
int x = i % bitmap.width + slot->bitmap_left;
int y = i / bitmap.width - slot->bitmap_top;
if (bitmap.buffer[i] != 0)
pset(win, x, y); /* 点を描く */
}
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
}
newrgbcolor(win, 0, 0, 255);
fillcirc(win, draw_x, draw_y, 3, 3);/* 基準点 */
copylayer(win, 1, 0); /* レイヤ1をレイヤ0に瞬時にコピー */
ggetch(); /* キー入力があるまで待つ */
gclose(win); /* グラフィックス用ウィンドゥを閉じる */
error = FT_Done_Face( face );
if (error)
{
fprintf(stderr, "error FT_Done_Face\n");
exit(EXIT_FAILURE);
}
error = FT_Done_FreeType(library);
if (error)
{
fprintf(stderr, "error FT_Done_FreeType\n");
exit(EXIT_FAILURE);
}
return 0;
}
アンチエリアシングなし
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <eggx.h> /* EGGX を使う時に必要 */
int strwlen(char *buf)
{
// LC_CTYPE をネイティブロケールに変更
if( setlocale( LC_CTYPE, "" ) == NULL ){
fprintf(stderr, "do not set locale.\n");
exit(EXIT_FAILURE);
}
int i = 0;
int count = 0;
while( buf[i] != '\0' ){
int res = mblen( &buf[i], MB_CUR_MAX );
if( res < 0 ){
fprintf(stderr, "Contains illegal characters.\n");
exit(EXIT_FAILURE);
}
i += res;
count++;
}
return count;
}
#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))
int main(int argc,char *argv[]){
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
int error,win;
char text[] = "hello,world!\nこんにちは世界\nrotation\n回転";
wchar_t ws[256]; /* ワイド文字保存用 */
int num_chars = strwlen(text);
int draw_x = 100;
int draw_y = 200;
int len = mbstowcs( ws, text, SIZE_OF_ARRAY(ws) );
if( len == -1 ){
fprintf(stderr, "mbstowcs error\n");
exit( EXIT_FAILURE );
}
gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
win = gopen(500,400); /* 1000x600 ピクセルのグラフィックス用ウィンドゥを開く */
layer(win, 0, 1); /* 描画レイヤを設定 */
// FreeTypeの初期化とTrueTypeフォントの読み込み
error = FT_Init_FreeType( &library );
if(error) {
fprintf(stderr,"error FT_Init_FreeType\n");
exit(EXIT_FAILURE);
}
error = FT_New_Face( library, "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", 0, &face );
if(error == FT_Err_Unknown_File_Format) {
fprintf(stderr,"unsupport fonts format\n");
exit(EXIT_FAILURE);
} else if(error) {
fprintf(stderr,"fonts file not found\n");
exit(EXIT_FAILURE);
}
slot = face->glyph;
error = FT_Set_Pixel_Sizes( face, 0, 60 ); //ピクセル単位でサイズ指定
//error = FT_Set_Char_Size( face, 0, 16 * 64, 300, 300); //ポイント単位でサイズ指定
if(error) {
fprintf(stderr,"FT_Set_Pixel_Sizes\n");
exit(EXIT_FAILURE);
}
FT_Matrix matrix; /* transformation matrix */
double angle = M_PI/4.0; /* 回転角度 */
FT_Vector pen; /* untransformed origin */
int line=0;
/* set up matrix */
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
pen.x = draw_x*64;
pen.y = (-draw_y)*64;
for (int n = 0;n < num_chars; n++ ){
FT_Bitmap bitmap;
FT_Set_Transform( face, &matrix, &pen );
switch(ws[n]) {
case '\r':
pen.x = draw_x*64 + cos(angle-M_PI/2) * line * (face->size->metrics.height);
pen.y = -draw_y*64 + sin(angle-M_PI/2) * line * (face->size->metrics.height);
break;
case '\t': /*tabは正しく計算していません */
pen.x = pen.x - sin(angle-M_PI/2)*(face->size->metrics.max_advance);
pen.y = pen.y + cos(angle-M_PI/2)*(face->size->metrics.max_advance);
break;
case '\n':
line++;
pen.x = draw_x*64 + cos(angle-M_PI/2) * line * (face->size->metrics.height);
pen.y = -draw_y*64 + sin(angle-M_PI/2) * line * (face->size->metrics.height);
//(face->size->metrics.height>>6) 1文字の最大高さ 次の行のベースライン 固定小数点 26.6 bit
break;
default:
// n文字目の文字をビットマップ化
error = FT_Load_Char( face, ws[n], FT_LOAD_RENDER |FT_LOAD_MONOCHROME );// 横書き アンチエリアシングなし
if(error) {
fprintf(stderr,"FT_Load_Char error\n");
exit(EXIT_FAILURE);
}
bitmap = slot->bitmap;
newrgbcolor(win,255,255,255);/*白色*/
for( int loopy = 0; loopy < bitmap.rows ; loopy++){
for(int byte_index=0;byte_index<bitmap.pitch;byte_index++) {
int byte_value,rowstart,end_loop,num_bits_done;
byte_value = bitmap.buffer[loopy*bitmap.pitch+byte_index];
num_bits_done = byte_index*8;
rowstart = loopy*bitmap.width + byte_index*8;
if(8 > (bitmap.width - num_bits_done)) {
end_loop = bitmap.width - num_bits_done;
} else {
end_loop = 8;
}
for(int bit_index=0;bit_index<end_loop;bit_index++) {
int bit = byte_value & (1<<(7-bit_index));
if(bit!=0) {
int x = (bit_index+rowstart)%bitmap.width + slot->bitmap_left;
int y = (bit_index+rowstart)/bitmap.width - slot->bitmap_top;
pset(win,x,y); /* 点を描く */
}
}
}
}
pen.x += slot->advance.x ;
pen.y += slot->advance.y ;
}
}
newrgbcolor(win,0,0,255);
fillcirc (win,draw_x,draw_y,3,3); /* 基準点 */
copylayer(win, 1, 0); /* レイヤ1をレイヤ0に瞬時にコピー */
ggetch(); /* キー入力があるまで待つ */
gclose(win); /* グラフィックス用ウィンドゥを閉じる */
error = FT_Done_Face( face );
if(error) {
fprintf(stderr,"error FT_Done_Face\n");
exit(EXIT_FAILURE);
}
error = FT_Done_FreeType( library );
if(error) {
fprintf(stderr,"error FT_Done_FreeType\n");
exit(EXIT_FAILURE);
}
return 0;
}
実行結果
参考