スポンサーリンク

FreeType2でBold、Italicの文字を描画(2)

Bold、Italicなどが別々のファイルに分かれている場合、各ファイルのfamily_nameがフォントの種類を特定する指標となり、同じフォントのfamily_nameは共通しているので、family_nameごとに纏めた辞書を作れば、特定のfamillyに対してスタイルを選択することができる。

#include <iostream>

#include <vector>
#include <fstream>
#include <filesystem>
#include <unordered_map>

#include <ft2build.h>
#include FT_FREETYPE_H

#pragma warning(disable:4996)

#ifdef _DEBUG
#pragma comment(lib,"freetyped.lib")
#else
#pragma comment(lib,"freetype.lib")
#endif


//! @brief PBM(1byte,テキスト)を書き込む
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む
void pbmP1_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, "P1\n%d\n%d\n", width, height);

    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] ? 0 : 1);
            k++;
        }
        fprintf(fp, "\n");
    }

    fclose(fp);
}

bool render(FT_Face face, FT_ULong character) {

    //文字コード指定
    FT_Error error = FT_Select_Charmap(
        face,               // target face object
        FT_ENCODING_UNICODE // エンコード指定
    );


    if (error == FT_Err_Unknown_File_Format)
        return false;
    else if (error)
        return false;

    //この二つの値でフォントサイズ調整
    FT_F26Dot6 fontsize = 16 * 64*2;
    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


    FT_UInt char_index = FT_Get_Char_Index(face, character);

    // グリフ(字の形状)読込
    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);

    int Width = face->glyph->bitmap.width;
    int Height = face->glyph->bitmap.rows;


    char filename[1024];
    sprintf(filename, "C:\\test\\freetypetest_%s.pbm", face->style_name);

    pbmP1_Write(// ファイル保存
        filename,
        Width,
        Height,
        face->glyph->bitmap.buffer
    );

}

// filesystemでフォントファイル名一覧を取得する
std::vector<std::string> getFontFileList(const std::string& fontdir) {
    namespace fs = std::filesystem;

    std::vector<std::string> fontList;

    if (!fs::exists(fontdir) || !fs::is_directory(fontdir)) {
        std::cerr << "Directory does not exist: " << fontdir << std::endl;
        return fontList;
    }

    // Iterate through the directory
    for (const auto& entry : fs::directory_iterator(fontdir)) {
        if (entry.is_regular_file()) {
            auto path = entry.path();
            fontList.push_back(path.string());
        }
    }

    return fontList;
}

// フォントファイルからフォントを取得し、フォントファミリでグループ化する
std::unordered_map<std::string, std::vector<std::pair<std::string, FT_Face>> > getFonts(FT_Library library,const std::vector<std::string>& flist) {

    std::unordered_map<
        std::string, 
        std::vector< std::pair<std::string,FT_Face> > > fontmap;

    for (const auto& file : flist) {

        FT_Face face;      // handle to face object

        // フォントファイル読み込み
        FT_Error error = FT_New_Face(
            library,
            file.c_str(),
            0,
            &face
        );
        if(error)
            continue;

        fontmap[face->family_name].push_back({ file,face });// ファミリ名をキーとしてフェイスを保存

    }

    return fontmap;

}
int main()
{

    FT_Library library; // handle to library
    FT_Error error;

    error = FT_Init_FreeType(&library);
    if (error)
        return -1;

    std::vector<std::string> flist = getFontFileList("C:\\Windows\\Fonts\\");

    // フォントファミリでグループ化したフォントリストを取得
    auto famillies = getFonts(library, flist);

    // arialフォントのファミリ名で取得
    const auto& arial = famillies["Arial"];
    for( const auto& [file,face] : arial){
        std::cout << face->style_name << std::endl;
        render(face, wchar_t(L'A'));
    }

    // フォント解放
    for (auto& familly : famillies) {
        for (std::pair<std::string,FT_Face>& tf : familly.second) {
            FT_Face face = tf.second;
            FT_Done_Face(face);
        }
    }


    FT_Done_FreeType(library);
}

出力

Regular
Bold
Bold Italic
Italic
Narrow
Narrow Bold
Narrow Bold Italic
Narrow Italic
Black

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: