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); }