C言語ではキー入力を受け取るときに最後に[Enter]キーを押す必要があります。[Enter]キーを押さなくてもキー入力を受け取るプログラムのサンプルです。同じことはncurses ライブラリでもできますが、キー入力のみでよい場合は、このプログラムを組み込むだけでOKです。プログラムの作成はRaspberry Pi4で行っています。
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <unistd.h> #include <signal.h> #include <fcntl.h> /* * 押されたキーの値を返す * ブロックしない。キーが押されていない場合は戻り値は0となる。 */ int getkeyNB(void) { struct termios oldt, newt; int ch0,ch1,ch2,ch3,ch4; int ret,oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_iflag = ~( BRKINT | ISTRIP | IXON ); newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL ); newt.c_cc[VTIME] = 0; /* キャラクタ間タイマを使わない */ newt.c_cc[VMIN] = 1; /* 1文字来るまで,読み込みをブロックする */ //newt.c_cc[VINTR] = 0; /* Ctrl-c */ //newt.c_cc[VQUIT] = 0; /* Ctrl-\ */ //newt.c_cc[VERASE] = 0; /* del */ //newt.c_cc[VKILL] = 0; /* @ */ //newt.c_cc[VEOF] = 4; /* Ctrl-d */ //newt.c_cc[VSWTC] = 0; /* '\0' */ //newt.c_cc[VSTART] = 0; /* Ctrl-q */ //newt.c_cc[VSTOP] = 0; /* Ctrl-s */ //newt.c_cc[VSUSP] = 0; /* Ctrl-z */ //newt.c_cc[VEOL] = 0; /* '\0' */ //newt.c_cc[VREPRINT] = 0; /* Ctrl-r */ //newt.c_cc[VDISCARD] = 0; /* Ctrl-u */ //newt.c_cc[VWERASE] = 0; /* Ctrl-w */ //newt.c_cc[VLNEXT] = 0; /* Ctrl-v */ //newt.c_cc[VEOL2] = 0; /* '\0' */ if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } /* ノンブロックモードに設定 */ oldf = fcntl(STDIN_FILENO, F_GETFL, 0); if(oldf<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } if(fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK)<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } ch0 = getchar(); if(ch0==0x1B) { //矢印キー Fnキーなどの取得 取得できないキーもある ch1 = getchar(); ch2 = getchar(); if(ch2==0x32) { ch3 = getchar(); if(ch3==0x7e) { ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } } else if(ch2==0x31) { ch3 = getchar(); ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) { ch3 = getchar(); ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ret = (ch0<<16) | (ch1<<8) | ch2; } } else if(ch0 != EOF) { ret = ch0; } else { ret = 0; } if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } if(fcntl(STDIN_FILENO, F_SETFL, oldf)<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGINT); } /*if(ret == 0x1a) { //[Ctrl]+[Z] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGTSTP); }*/ return ret; } /* * 押されたキーの値を返す * ブロックする。キーが押されるまで戻らない。 */ int getkey(void) { struct termios oldt, newt; int ch0,ch1,ch2,ch3,ch4; int ret; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_iflag = ~( BRKINT | ISTRIP | IXON ); newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL ); newt.c_cc[VTIME] = 0; /* キャラクタ間タイマを使わない */ newt.c_cc[VMIN] = 1; /* 1文字来るまで,読み込みをブロックする */ if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } ch0 = getchar(); if(ch0==0x1B) { //矢印キー Fnキーなどの取得 取得できないキーもある ch1 = getchar(); ch2 = getchar(); if(ch2==0x32) { ch3 = getchar(); if(ch3==0x7e) { ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } } else if(ch2==0x31) { ch3 = getchar(); ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) { ch3 = getchar(); ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ret = (ch0<<16) | (ch1<<8) | ch2; } } else if(ch0 != EOF) { ret = ch0; } else { ret = 0; } if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGINT); } return ret; } int main(int argc,char *argv[]) { int key; while (1) { //key = getkeyNB(); key = getkey(); if (key!=0) { printf("key code %4x\n",key); }else{ printf("wait\n"); usleep(100000); } } return 0; }
参考
ncurses は、端末に依存しない形式でテキストユーザインタフェース (TUI) を作成するためのライブラリです。ncursesのサンプルプログラムを集めてみました。リストはリンク先からの借り物です。 プログラムの作成はRaspberry Pi4で行っています。
インストールとコンパイル
インストール $ sudo apt install libncurses-dev コンパイル $ gcc -o hoge hoge.c -lncurses
リスト1
#include <ncurses.h> #include <stdio.h> #include <string.h> int main(int argc,char *argv[]) { initscr();//初期化 noecho(); //キーが入力されても表示しない curs_set(0);//カーソルを非表示 mvprintw(12, 30, "Hello World!"); while (true) { int ch = getch(); if (ch == 'q') break; } endwin();//終了処理 retuen 0; }
リスト2
#include <ncurses.h> #include <stdio.h> #include <string.h> int main(int argc,char *argv[]) { int x, y, w, h; char *str="Hello World"; int key; initscr();//初期化 noecho();//キー入力した文字の非表示モード curs_set(0);//カーソルを非表示 cbreak();//[Enter] キー不要の入力モード keypad(stdscr, TRUE);//特殊キー(カーソルキーなど)を有効化 //stdscr は端末画面を表わす定数である. 標準出力 stdout の curses 版だと考えればよい. getmaxyx(stdscr, h, w);//端末のサイズを取得 注意 ポインタ渡しではない y = h/2; x = (w-strlen(str))/2; while (1) { erase();//画面の消去 move(y, x);//表示位置指定 addstr(str);//文字を出力する refresh();//画面の再表示 key = getch();//キー入力 if (key == 'q') break; switch (key) { case KEY_UP: y--; break; case KEY_DOWN: y++; break; case KEY_LEFT: x--; break; case KEY_RIGHT: x++; break; } } endwin();//終了処理 return 0; }
リスト3
#include <ncurses.h> #include <stdio.h> #include <string.h> int main(int argc,char *argv[]) { // 端末の準備 initscr(); // 色の準備 start_color(); init_pair(1, COLOR_RED, COLOR_BLUE); // 色1 は青地に赤文字 init_pair(2, COLOR_GREEN, COLOR_BLUE); // 色2 は青地に緑文字 init_pair(3, COLOR_YELLOW, COLOR_BLUE); // 色3 は青地に黄文字 init_pair(10, COLOR_WHITE, COLOR_BLUE); // 色10 は青地に白文字 bkgd(COLOR_PAIR(10)); // 背景は色10 // 表示 attrset(COLOR_PAIR(1)); // 色1 を使う mvaddstr(5, 5, "Hello World"); attrset(COLOR_PAIR(2)); // 色2 を使う mvaddstr(5, 25, "Hello World"); attrset(COLOR_PAIR(3)); // 色3 を使う mvaddstr(5, 45, "Hello World"); attrset(COLOR_PAIR(1) | A_BOLD); // 色&強調表示 mvaddstr(6, 5, "Hello World"); attrset(COLOR_PAIR(2) | A_BOLD); mvaddstr(6, 25, "Hello World"); attrset(COLOR_PAIR(3) | A_BOLD); mvaddstr(6, 45, "Hello World"); attrset(COLOR_PAIR(1) | A_REVERSE); // 色&反転表示 mvaddstr(7, 5, "Hello World"); attrset(COLOR_PAIR(2) | A_REVERSE); mvaddstr(7, 25, "Hello World"); attrset(COLOR_PAIR(3) | A_REVERSE); mvaddstr(7, 45, "Hello World"); attrset(COLOR_PAIR(1) | A_REVERSE | A_BOLD); // 色&反転&強調 mvaddstr(8, 5, "Hello World"); attrset(COLOR_PAIR(2) | A_REVERSE | A_BOLD); mvaddstr(8, 25, "Hello World"); attrset(COLOR_PAIR(3) | A_REVERSE | A_BOLD); mvaddstr(8, 45, "Hello World"); // 終了 getch(); endwin(); return (0); }
参考
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; }
実行結果

参考
True type fontをbitmapにレンダリングするプログラムを作成しました。レンダリングにはFreeTypeライブラリを使用しました。プログラムの作成はRaspberry Pi4で行っています。画像の表示にはEGGX / ProCALLライブラリを使用しました。
表示が2値の場合のプログラムです。2値なのでアンチエリアシングができません。変換データは8 pixel が 1 byte にパックされます。
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.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[] = "こんにちは、世界!";
wchar_t ws[256]; /* ワイド文字保存用 */
int pen_x, pen_y;
int num_chars = strwlen(text);
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(1000,200); /* 1000x200 ピクセルのグラフィックス用ウィンドゥを開く */
//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, 120 ); //ピクセル単位でサイズ指定
//error = FT_Set_Char_Size( face, 0, 16 * 64, 300, 300); //ポイント単位でサイズ指定
if(error) {
fprintf(stderr,"FT_Set_Pixel_Sizes\n");
exit(EXIT_FAILURE);
}
pen_x = 10; // 文字の表示座標 左下のベースライン
pen_y = 150;
newrgbcolor(win,0,0,255);
drawline(win,pen_x,pen_y,1000,pen_y);
for (int n = 0;n < num_chars; n++ ){
FT_Bitmap bitmap;
// n文字目の文字をビットマップ化
//error = FT_Load_Char( face, text[n], FT_LOAD_VERTICAL_LAYOUT|FT_LOAD_RENDER );//縦書き
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 + pen_x + slot->bitmap_left;
int y = (bit_index+rowstart)/bitmap.width + pen_y - slot->bitmap_top + (face->size->metrics.descender >>6);
pset(win,x,y); /* 点を描く */
}
}
}
}
pen_x += slot->advance.x >> 6;
pen_y += slot->advance.y >> 6;
}
//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;
}
実行結果

参考
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 <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[] = "こんにちは、世界!"; wchar_t ws[256]; /* ワイド文字保存用 */ int pen_x, pen_y; int num_chars = strwlen(text); 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(1000,200); /* 1000x200 ピクセルのグラフィックス用ウィンドゥを開く */ //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, 120 ); //ピクセル単位でサイズ指定 //error = FT_Set_Char_Size( face, 0, 16 * 64, 300, 300); //ポイント単位でサイズ指定 if(error) { fprintf(stderr,"FT_Set_Pixel_Sizes\n"); exit(EXIT_FAILURE); } pen_x = 10; // 文字の表示座標 左下のベースライン pen_y = 150; newrgbcolor(win,0,0,255); drawline(win,pen_x,pen_y,1000,pen_y); for (int n = 0;n < num_chars; n++ ){ int i; FT_Bitmap bitmap; // n文字目の文字をビットマップ化 //error = FT_Load_Char( face, ws[n], FT_LOAD_VERTICAL_LAYOUT|FT_LOAD_RENDER );//縦書き 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+pen_x + slot->bitmap_left; int y = i / bitmap.width+pen_y - slot->bitmap_top + (face->size->metrics.descender >>6); pset(win,x, y); /* 点を描く */ } pen_x += slot->advance.x >> 6; pen_y += slot->advance.y >> 6; } //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; }
実行例

参考