忘備録-備忘録

技術的な備忘録

True type fontのレンダリング その7

2020-04-21 22:30:34 | Linux
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のレンダリング その6

2020-04-21 22:01:20 | Linux
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のレンダリング その5

2020-04-21 21:52:01 | Linux
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;
}

実行例


参考


True type fontのレンダリング その4

2020-04-21 21:12:37 | Linux
True type fontをbitmapにレンダリングするプログラムを作成しました。レンダリングにはFreeTypeライブラリを使用しました。プログラムの作成はRaspberry Pi4で行っています。画像の表示にはEGGX / ProCALLライブラリを使用しました。 

前回のプログラムは",pq"などの文字は指定した座標の下にはみ出してしまいます。これを指定の範囲に収めます。
face->size->metrics.descender ベースラインの下にはみ出す長さ
face->size->metrics.height フォントの高さ
face->size->metrics.max_advance フォントの最大幅
これらの値は26.6の固定小数点になっています。

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ft2build.h>
#include FT_FREETYPE_H

#include <eggx.h> /* EGGX を使う時に必要 */

int main(int argc,char *argv[]){
    FT_Library library;
    FT_Face    face;
    FT_GlyphSlot slot;
    int error,win;
    char text[] = "hello,world!";
    int pen_x, pen_y;
    int num_chars = (int)strlen( text);

    gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
    win = gopen(800,400); /* 800x400 ピクセルのグラフィックス用ウィンドゥを開く */
    //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,800,pen_y);
    for (int n = 0;n < num_chars; n++ ){
        int i;
        FT_Bitmap bitmap;

        // n文字目の文字をビットマップ化
        //error = FT_Load_Char( face, text[n], FT_LOAD_VERTICAL_LAYOUT|FT_LOAD_RENDER );//縦書き
        error = FT_Load_Char( face, text[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;
}

実行結果


参考


True type fontのレンダリング その3

2020-04-21 20:51:01 | Linux
True type fontをbitmapにレンダリングするプログラムを作成しました。レンダリングにはFreeTypeライブラリを使用しました。プログラムの作成はRaspberry Pi4で行っています。画像の表示にはEGGX / ProCALLライブラリを使用しました。 

文字の大きさが違うのに同じ位置から表示を始めてしまったために表示がおかしくなっています。文字ごとのbitmapの表示位置は、
slot->bitmap_left
slot->bitmap_top
に保存されます。
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ft2build.h>
#include FT_FREETYPE_H

#include <eggx.h> /* EGGX を使う時に必要 */

int main(int argc,char *argv[]){
    FT_Library library;
    FT_Face    face;
    FT_GlyphSlot slot;
    int error,win;
    char text[] = "hello,world!";
    int pen_x, pen_y;
    int num_chars = (int)strlen( text);

    gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
    win = gopen(800,400); /* 800x400 ピクセルのグラフィックス用ウィンドゥを開く */
    //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,800,pen_y);
    for (int n = 0;n < num_chars; n++ ){
        int i;
        FT_Bitmap bitmap;

        // n文字目の文字をビットマップ化
        //error = FT_Load_Char( face, text[n], FT_LOAD_VERTICAL_LAYOUT|FT_LOAD_RENDER );//縦書き
        error = FT_Load_Char( face, text[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;
            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;
}

実行結果


正しく表示されました。

参考