トップページ > 記事閲覧
CheckFontName : バグ?
名前:8127 日時: 2018/06/13 19:52

いつもお世話になっております。 CheckFontNameについて、フォントの読み込み方によっては、 正常に読み込めている(DrawFormatStringToHandleで正しく描画される)にもかかわらずCheckFontNameがFALSEを返すことがあったので報告します。 以下の再現コードのWinMain中のfontLoad(0);をfontLoad(1);に書き換えることで2通りのフォントロード方法を試すことができます。 (Dxアーカイブ中の.ttfを使いたかったのでfontLoad(0)を採用したいと思っています) ですが、fontLoad(0)のとき、DrawFormatStringで正しく描画される(比較文字列と異なるフォントで描画される)にもかかわらず CheckFontNameがFALSEを返してしまいます。("Fontがインストールされていません"と表示されてしまう) ※fontLoad(1);の場合は意図通りに動作します。 ・・・可能性は低いと思いますがフォントファイル特有の問題の可能性があるので一応DL先を張っておきます(フリーです) tps://ja.osdn.net/projects/ume-font/ 環境はVS2017最新更新、DXライブラリ暫定最新版です。 よろしくお願いします。 #include <iostream> #include <memory> #include "DxLib.h" void dxlibInit() { ChangeWindowMode(true); //ウインドウモードにする SetWindowSize(640, 480); if (DxLib_Init() == -1) // DXライブラリ初期化処理 { return; // エラーが起きたら直ちに終了 } SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定 } void drawString(const char *fontName) { if (CheckFontName(fontName) == FALSE) { printfDx("Font[%s]がインストールされていません\n", fontName); } const int handle = CreateFontToHandle(fontName, 24, 0); static int y = 100; DrawStringToHandle(0, y, "テスト", GetColor(255, 0, 0), handle); DeleteFontToHandle(handle); y += 50; } constexpr LPCSTR fontPath = "ume-pgs4.ttf"; void fontLoad(int flag) { if (flag == 0) { //新方式(Dxアーカイブからも可能?) int handle = FileRead_fullyLoad(fontPath); const auto size = (size_t)FileRead_fullyLoad_getSize(handle); auto buffer = std::make_unique<char[]>(size); memcpy_s(buffer.get(), size, FileRead_fullyLoad_getImage(handle), size); FileRead_fullyLoad_delete(handle); //編集で追加(解放忘れ) DWORD num; if (0 == AddFontMemResourceEx(buffer.get(), (DWORD)size, 0, &num)) { // フォント読込エラー処理 printfDx("フォント読込失敗"); } } else if (flag == 1) { if (AddFontResource(fontPath) <= 0) { printfDx("フォント読込失敗\n"); } } } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { constexpr char *fontName = "梅PゴシックS4"; dxlibInit(); fontLoad(0); drawString(fontName); //わざと存在しないフォントを指定してデフォルトで描画させる //Dxライブラリには「フォントが見つからないならデフォルトで描画」という変な挙動があるため //デフォルトと比較しない限り、意図通りのフォントで描画されてるか確認しづらい drawString("怒首領蜂"); // 裏画面の内容を表画面に反映させる ScreenFlip(); // キー入力待ち WaitKey(); RemoveFontResource(fontPath); return 0; }
メンテ

Page: 1 |

Re: CheckFontName : バグ? ( No.1 )
名前:管理人 日時:2018/06/14 02:43

手元の環境で載せていただいたプログラムを実行してみましたところ、 手元の環境では fontLoad(0) の場合も fontLoad(1) の場合も 正常に動作してしまいました( 梅PゴシックS4 の CheckFontName は成功しました ) すみません、正常に動作しているので、何が原因かちょっと想像がつきません・・・ FileRead_fullyLoad が失敗している、ということは無いでしょうか? ( その場合 AddFontMemResourceEx が失敗するはずですので違うとは思いますが・・・ )
メンテ
Re: CheckFontName : バグ? ( No.2 )
名前:8127 日時:2018/06/14 11:57

管理人様、 調査ありがとうございます。 ・FileRead_fullyLoadは成功していました。 こちらの環境でも、実験を繰り返しているうちに再現しなくなってしまっているのですが、 PCを再起動したところまた再現しました。管理人様もお手数ですがPCを再起動した直後にもう一度テストしていただけますか。 ・(問題が再現するときに)EnumFontNameを使って利用可能な日本語フォントを列挙しました。 その中に、梅PゴシックS4は含まれていませんでした (画像を見ると分かる通り、それであっても文字はデフォルトと異なる書体で描画されています) ttps://i.imgur.com/JQRpEfD.png #include <iostream> #include <memory> #include "DxLib.h" void dxlibInit() { ChangeWindowMode(true); //ウインドウモードにする SetWindowSize(640, 480); if (DxLib_Init() == -1) // DXライブラリ初期化処理 { return; // エラーが起きたら直ちに終了 } SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定 } void printAllFont() { const int fontNum = EnumFontName(NULL, 0); auto nameBuffer = std::make_unique<char[]>(64 * fontNum); EnumFontName(nameBuffer.get(), fontNum); for (size_t i = 0; i < fontNum; ++i) { printfDx("%s, ", nameBuffer.get() + 64 * i); } printfDx("\n"); } void drawString(const char *fontName) { if (CheckFontName(fontName) == FALSE) { printfDx("Font[%s]がインストールされていません\n", fontName); } printAllFont(); const int handle = CreateFontToHandle(fontName, 24, 0); static int y = 300; DrawStringToHandle(0, y, "テスト", GetColor(255, 0, 0), handle); DeleteFontToHandle(handle); y += 50; } constexpr LPCSTR fontPath = "ume-pgs4.ttf"; void fontLoad(int flag) { if (flag == 0) { //新方式(Dxアーカイブからも可能?) int handle = FileRead_fullyLoad(fontPath); if (handle == -1) { printfDx("fullyload失敗"); return; } const auto size = (size_t)FileRead_fullyLoad_getSize(handle); auto buffer = std::make_unique<char[]>(size); memcpy_s(buffer.get(), size, FileRead_fullyLoad_getImage(handle), size); FileRead_fullyLoad_delete(handle); DWORD num; if (0 == AddFontMemResourceEx(buffer.get(), (DWORD)size, 0, &num)) { // フォント読込エラー処理 printfDx("フォント読込失敗"); } } else if (flag == 1) { if (AddFontResource(fontPath) <= 0) { printfDx("フォント読込失敗\n"); } } } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { constexpr char *fontName = "梅PゴシックS4"; dxlibInit(); fontLoad(0); drawString(fontName); //わざと存在しないフォントを指定してデフォルトで描画させる //Dxライブラリには「フォントが見つからないならデフォルトで描画」という(変な?)挙動があるため //デフォルトと比較しない限り、意図通りのフォントで描画されてるか確認しづらい drawString("怒首領蜂"); // 裏画面の内容を表画面に反映させる ScreenFlip(); // キー入力待ち WaitKey(); RemoveFontResource(fontPath); DxLib_End(); return 0; }
メンテ
Re: CheckFontName : バグ? ( No.3 )
名前:8127 日時:2018/06/14 11:59

あと、梅Pゴシックは割と有名なフリーフォントですので、お使いのPCに既にインストールされているということはありませんか。
メンテ
Re: CheckFontName : バグ? ( No.4 )
名前:管理人 日時:2018/06/17 00:42

> PCを再起動したところまた再現しました。管理人様もお手数ですがPCを再起動した直後にもう一度テストしていただけますか。 PCを再起動した直後にテストしたところ、私の環境でも現象を確認することができました そして、調べた結果ですが、原因不明、という結論に至りました OS のバグなのか、仕様なのか、何か見落としがあるのかは分かりませんが、CheckFontName や EnumFontName の中では フォントを列挙するための API である EnumFontFamiliesEx を使用しているのですが、こちらの関数が 8127さんの検証に近い以下のような挙動となっていました ・パソコン起動直後では AddFontMemResourceEx や AddFontResource で追加したフォントを検出しない ・少し時間が経つと AddFontResource で追加したフォントは検出するようになる ・大分時間が経つと AddFontMemResourceEx で追加したフォントも検出するようになる ・AddFontResource で追加する実行を行った後、AddFontMemResourceEx で追加すると、1度だけは検出されることがある( 必ずではない ) ・EnumFontFamiliesEx でフォントが検出されなくても CreateFont ( ←フォントハンドルを作成する API ) では問題なく追加したフォントを使用することができる Microsoft の API リファレンスの説明を見てもネットで調べてもこの現象に関する情報はなく、 正直お手上げの状態です なので、申し訳ありませんが AddFontMemResourceEx や AddFontResource で追加したフォントが CheckFontName で 検出されないことがあるという本件の現象は仕様とさせてください m(_ _;m
メンテ
Re: CheckFontName : バグ? ( No.5 )
名前:8127 日時:2018/06/17 23:52

管理人さま、 >本件の現象は仕様とさせてください m(_ _;m 了解しました。OS(Win32API?)のバグらしいのですね・・・ ところで、そもそもCheckFontNameを使った理由が、 「フォントの検索に失敗した場合でもCreateFontToHandleはデフォルトのフォントでハンドルを作成してしまい正常値が返ってくるので、 意図通りに成功したか分からなく、CheckFontNameを使い成功したかを取得したい」ということでした。 ですので、CreateFontToHandle時に意図通りにフォントが作成されたかを取得する方法を追加していただけませんか? (これならDxFontWin.cppのCreateFontToHandle_PFを変更すれば可能な気がします) // フォントハンドルを作成する // SuccessToFindFontNameが非NULLのとき、指定したフォントが見つかれば1を、デフォルトフォントで作成されたなら0を格納する int CreateFontToHandle(const TCHAR *FontName, nt Size, int Thick, int FontType = -1 , int CharSet = -1 , int EdgeSize = -1 , int Italic = FALSE , int Handle = -1 , int *SuccessToFindFontName = NULL) ; よろしくお願いします。
メンテ
Re: CheckFontName : バグ? ( No.6 )
名前:管理人 日時:2018/06/19 00:39

> ですので、CreateFontToHandle時に意図通りにフォントが作成されたかを取得する方法を追加していただけませんか? 私もその機能を追加したいのは山々なのですが、意図通りのフォントが作成できたか調べる術がないので、その機能を追加することができないのです (_ _;; ( Win32API の CreateFont が『指定したフォントが無かったらデフォルトのフォントでフォントハンドルを作成する』という仕様なので… ) なので、釈然としない処理となりますが、 『CheckFontName で存在しなかった場合は AddFontMemResourceEx などでフォントを追加して、  AddFontMemResourceEx で追加したフォントは CheckFontName で検出できなくても  CreateFontToHandle では正常に作成することができる』 ということを前提として処理を組むしかないと思います m(_ _;m
メンテ
Re: CheckFontName : バグ? ( No.7 )
名前:8127(解決) 日時:2018/06/19 20:33

管理人さま、 ご対応ありがとうございます。 CreateFontToHandle_PFを流し読みする限りではデフォルト動作はDxlib側の処理だと思ったのですが、OS側の仕様でしたか・・・ 一応、GetDrawStringWidthToHandleの文字幅取得は機能するようなので、それでちょっと試してみます。 ありがとうございました。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存