トップページ > 記事閲覧
数字の等幅ライニングの設定
名前:was-blue.0793 日時: 2019/10/21 21:49

OpenTypeフォントの一部には、数字が等幅なものとプロポーショナルなものの2つを併せ持ったフォントがあります。 このフォントをDXフォントデータ化したり、CreateFontToHandleでフォントハンドルを作成する時、等幅のものを使う方法はありますか? よろしくお願いします。
メンテ

Page: 1 |

Re: 数字の等幅ライニングの設定 ( No.1 )
名前:管理人 日時:2019/10/22 06:14

> OpenTypeフォントの一部には、数字が等幅なものとプロポーショナルなものの2つを併せ持ったフォントがあります。 MSゴシック は等幅は『MSゴシック』、可変幅は『MSPゴシック』と、フォント名が異なりますが 同じフォント名で等幅と可変幅のフォントがあるのでしょうか? もしそうでしたら、よろしければ本件のフォントに該当するフォントを教えていただけないでしょうか? m(_ _)m
メンテ
Re: 数字の等幅ライニングの設定 ( No.2 )
名前:was-blue.0793 日時:2019/10/22 11:30

>>管理人さん OpenTypeは商業フォントに多い規格ですが、フリーフォントでも「Inter」や「Jost*」といったフォントが1つのフォントで等幅・プロポーショナルな数字の双方に対応します。 TrueTypeフォントだと1つのフォントファイルでは1つの文字につき1つの文字情報しか入れることができず、MSゴシックでは等幅・プロポーショナルで別フォントになっていますが、 OpenTypeフォントでは、1つのフォントファイルで1つの文字につき2つ以上の文字情報を入れることができるため、1つのフォントファイルで等幅・プロポーショナルな数字のフォント双方に対応できます。 rsms.me/inter/ indestructibletype.com/Jost.html
メンテ
Re: 数字の等幅ライニングの設定 ( No.3 )
名前:管理人 日時:2019/10/23 01:38

ご返答ありがとうございます 教えていただいたご情報を元に少し調べてみましたところ、現状では 『OpenTypeフォントに含まれる等幅な数字を使用する方法はありません( 必ずプロポーショナルな数字が使用されます )』 というご返答となりそうです m(_ _;m ( DXライブラリは OS( Windows )のAPIを使用して文字描画を行っているのですが、 その中にプロポーショナルな数字と等幅な数字を使い分けるための機能が無さそうです… ) ただ、数字を一文字づつ DrawString で描画して、一文字一文字の座標を自前で 指定することで疑似的に等幅に数字を描画することは可能です
メンテ
Re: 数字の等幅ライニングの設定 ( No.4 )
名前:was-blue.0793 日時:2019/12/06 16:34

>>管理人さん 数字を1文字ずつ描画して擬似的に等幅描画する方法は以前Qiitaで記事にしたのですが、別件でDXフォントファイルを使う文字列を1文字単位で分けて描画したら異常に重くなる現象がありました。 DXフォントファイルでは、どのようにしてグリフの情報を持っているのでしょうか? 以前"DXアーカイブの仕組みを利用し、中に画像形式でグリフを持っている"という話を聞いたと思うので、 画像形式で持っているとしたらDXフォントファイル限定で"等幅な数字グリフ"を作り出すことができそうだと思いましたが、大きな変更が必要になりそうでしょうか…… しかし、実現できればフォントの選択肢が一気に広がると思うので、個人的にはぜひご検討いただきたいところです……
メンテ
Re: 数字の等幅ライニングの設定 ( No.5 )
名前:管理人 日時:2019/12/07 01:21

> DXフォントファイルでは、どのようにしてグリフの情報を持っているのでしょうか? DXライブラリの通常の文字描画処理と同じ方法( OSのAPI )で文字の画像情報を取得して それを画面に描画する代わりにファイルに保存しているのがDXフォントファイルですので、 OSのAPIで等幅の数字の画像情報を取得することができない以上、DXフォントファイルでも やはり等幅な数字を使うことはできません
メンテ
Re: 数字の等幅ライニングの設定 ( No.6 )
名前:was-blue.0793 日時:2019/12/07 02:22

>>管理人さん グリフのデータを画像データに起こしているとすれば、コマンドライン引数を追加して指定した文字の文字幅が指定した1つの文字より狭い場合はその文字の文字幅と合わせることで実現できるのではないかと考えました。 フォントファイルから得たグリフの画像データの文字幅が指定した1文字の文字幅より狭い場合、その文字の画像データの左右に均等に空白を付けた画像データを格納すれば実現できそうと思いますが、 これまでのDXフォントファイルと構造が変わってしまう可能性があるという問題もありそうです。 例えば、「/Q"012345679" /L"8"」という引数を指定すると、"8"以外の数字の文字幅が"8"より狭い場合、左右に均等に空白をつけます。 格納されるグリフの画像データに均等に左右に空白を作る変更のコストが低ければ、この機能の実装を要望します。
メンテ
Re: 数字の等幅ライニングの設定 ( No.7 )
名前:管理人 日時:2019/12/07 17:32

うーん、フォントファイルにフォントから得られる情報ではないデータはなるべく増やしたくありません… No.3 でも申し上げましたが、一文字づつ DrawString で描画すれば現状でも等幅で数字を描画することはできるのですが、 それをされたくない事情があるのでしょうか?
メンテ
Re: 数字の等幅ライニングの設定 ( No.8 )
名前:was-blue.0793 日時:2019/12/08 17:57

>>管理人さん 1文字ずつ描画する方法は、フォントハンドルを使って文字数が多い文字列を描画すると異常に重くなる現象があります。 しかし、フォントハンドルを使わずに描画するとこの問題は発生しません。 //文字列は実際は100文字以上のかなり長い文字列 string src = u8"長文"; int fonthandle = LoadFontDataToHandle("fontdata.dft", 0); int pos = 0; for (size_t i = 0, is = src.length(); i < is; i += GetCharBytes(DX_CHARCODEFORMAT_UTF8, src.substr(i,string::npos).c_str())) { //1文字抜き出す string ch = src.substr(i, GetCharBytes(DX_CHARCODEFORMAT_UTF8, src.substr(i, string::npos))); DrawStringToHandle(pos, 0, ch.c_str(), GetColor(255,255,255), fonthandle); pos += GetDrawStringWidthToHandle(ch, ch.length(), fonthandle); } substrに原因があるのではないかとも考えたのですが、フォントハンドルを使わない(ToHandleがつかない文字列描画関数)と重くならない理由が説明できないので、 別件になってしまうのですが、フォントハンドルを使って1文字ずつ描画すると異常に重くなる原因は何が考えられるでしょうか?
メンテ
Re: 数字の等幅ライニングの設定 ( No.9 )
名前:yumetodo 日時:2019/12/08 15:33

ん、GetCharBytesの使い方あってます?第二引数どこにいったので substrのコストを考えるならstd::string_viewをつかう+WithLen系関数を使って長さを渡すといいと思います。
メンテ
Re: 数字の等幅ライニングの設定 ( No.10 )
名前:was-blue.0793 日時:2019/12/08 17:58

>>yumetodoさん すいません!引数が足りなかったので修正しました!
メンテ
Re: 数字の等幅ライニングの設定 ( No.11 )
名前:管理人 日時:2019/12/08 22:52

> substrに原因があるのではないかとも考えたのですが、フォントハンドルを使わない(ToHandleがつかない文字列描画関数)と重くならない理由が説明できないので、 > 別件になってしまうのですが、フォントハンドルを使って1文字ずつ描画すると異常に重くなる原因は何が考えられるでしょうか? 1文字づつ描画する場合、一度に描画するよりは重いのは確かですが、 フォントハンドルを使用しない DrawString などの関数も内部で DrawStringToHandle を使用していますので フォントハンドルを使用する場合のみ重くなる、というのは考えにくい現象です 異常に重いとのことですが、具体的にはどのくらいでしょうか? 重くなる原因、というより、フォントハンドルを使用する場合と、しない場合で重さが異なる原因として考えられるのは ・フォントのサイズが大きい ( DrawString で試した際は文字が小さかったから軽かった、という可能性 ) ・フォントの違いによるもの ( フォントハンドルを使用する場合も『MS ゴシック』だったら軽い、という可能性 ) でしょうか… なので、一度フォントハンドルを使用しない場合と同じ条件( CreateFontToHandle( NULL, 16, 0, DX_FONTTYPE_NORMAL ); で作成したフォントハンドルを使う ) でも異常に重くなってしまうかお試しいただけないでしょうか? m(_ _;m
メンテ
Re: 数字の等幅ライニングの設定 ( No.12 )
名前:was-blue.0793 日時:2019/12/09 18:55

>>管理人さん 当該プロジェクトでは、当初DXフォントデータからフォントハンドルを作成して1文字ずつ描画したところ10FPSを切るほどの異常な重さがみられ、 アンチエイリアスをなくしたり、フォントサイズを小さくして対応しても改善されませんでした。 ChangeFont・ChangeFontTypeで同じフォント、アンチエイリアスありに設定したところ、10FPSを切るような異常な重さはみられなくなり、60FPSで動作しました。 よって、DrawStringの実際の動作がCreateFontToHandleにおいてフォント名にNULL(nullptr)を渡して作られたフォントハンドルを使って描画したとすれば、 恐らくサイズ・アンチエイリアスの有無に関係はないものと思われ、DXフォントデータから文字データを呼び出してくる処理に何らかの原因があるものと思われます。 (この2関数の使い方は起動時に1度だけ呼び出すようにしています) 当初の事項については、「DXフォントデータに文字ごとの左右の空白の情報を追加する」のではなく、 「DXフォントデータに格納するグリフを画像データに変換したあと、その画像データ自体に空白を付加し、擬似的に等幅のグリフの画像データを作成する」というものを考えていましたが、 画像データ自体を操作することもコストが高そうに思えるので、難しいところです。
メンテ
Re: 数字の等幅ライニングの設定 ( No.13 )
名前:管理人 日時:2019/12/11 02:00

DXライブラリのパッケージの Tool\CreateDXFontData\Sample フォルダの中にある 『MS 明朝シフトJIS文字作成.bat』を実行して作成できる『MS 明朝シフトJIS.dft』を使用して 以下の1文字づつ文字を描画するテストプログラムを実行してみましたが、 手元の環境で 3000FPS くらい出ました #include "DxLib.h" const char *String = u8"あいうえおかきくけこさしすせそたちつてとABCDEFGHIJKLMN"; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int FPSCounter ; int DispFPS ; int FPSTime ; // UTF-8 を使用 SetUseCharCodeFormat( DX_CHARCODEFORMAT_UTF8 ) ; // ウィンドウモードで起動 ChangeWindowMode( TRUE ) ; // VSYNC待ちをしない SetWaitVSyncFlag( FALSE ) ; // 画面モードは 720p SetGraphMode( 1280, 720, 32 ) ; // DXライブラリ初期化処理 if( DxLib_Init() == -1 ) { return -1 ; } // DXフォントファイル読み込み int fonthandle = LoadFontDataToHandle( u8"MS 明朝シフトJIS.dft" ) ; // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; // FPS表示処理初期化 DispFPS = 0 ; FPSCounter = 0 ; FPSTime = GetNowCount() ; // メインループ while( ProcessMessage() == 0 ) { // 画面をクリア ClearDrawScreen() ; // 文字列を一文字づつ描画する処理 int pos = 0 ; int CharBytes ; for( size_t i = 0, is = strlenDx( String ); i < is; i += CharBytes ) { char ch[ 16 ] ; //1文字抜き出す CharBytes = GetCharBytes( DX_CHARCODEFORMAT_UTF8, String + i ) ; for( size_t j = 0; j < CharBytes; j++ ) { ch[ j ] = String[ i + j ] ; } ch[ CharBytes ] = 0 ; DrawStringToHandle(pos, 0, ch, GetColor(255,255,255), fonthandle); pos += GetDrawStringWidthToHandle(ch, CharBytes, fonthandle); } // FPS表示処理 FPSCounter ++ ; int NowCount = GetNowCount() ; if( NowCount - FPSTime >= 1000 ) { DispFPS = FPSCounter ; FPSCounter = 0 ; FPSTime = NowCount ; } DrawFormatString( 0, 100, GetColor(255,255,255), u8"FPS:%d", DispFPS ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリ使用の終了処理 DxLib_End() ; // ソフトの終了 return 0 ; } よろしければ was-blue.0793さんの環境でも『MS 明朝シフトJIS文字作成.bat』を実行して作成できる 『MS 明朝シフトJIS.dft』であれば異常に重くならないか試してみていただけないでしょうか? m(_ _)m
メンテ
Re: 数字の等幅ライニングの設定 ( No.14 )
名前:was-blue.0793 日時:2019/12/11 22:43

>>管理人さん 実際に10FPSを切るような重さになった文字列は500文字以上あるかなり長い文字列で、数文字程度だと1文字ずつ描画しても60FPSを出すことができます。 過去に擬似的に等幅化する方法を実装した時にその様子を録画した動画がありますが、10FPSを切るような重さは認められませんでした。 youtu.be/S3hVSrRmT3E 500文字以上描画しようとすると普通に描画しても重くなりそうではあり、通常の数値を擬似的に等幅化する方法と関連はないかもしれません……
メンテ
Re: 数字の等幅ライニングの設定 ( No.15 )
名前:管理人 日時:2019/12/12 01:46

> 500文字以上描画しようとすると普通に描画しても重くなりそうではあり、通常の数値を擬似的に等幅化する方法と関連はないかもしれません…… もし単純に DrawStringToHandle を 1文字つづ呼ぶのが重い、ということだとしますと、 純粋に1文字づつ DrawStringToHandle を呼ぶのではなく、数字のみを 1文字づつ描画する、 というようにすれば重くならないと思います ( 文字列の文字コードを1文字づつ数字かどうかをチェックして、数字ではなければ一度に描画するchar型配列に追加、 数字だったら、それまでに配列に貯めておいた文字を一度の DrawStringToHandle で描画( そして配列の文字列は空にする ) したあと数字を描画、数字を描画した後は、次の文字が数字かチェックして…と繰り返す ) ところで、500文字以上の文字列の中に含まれる数字のみ等幅化されたい、というのはなかなか特殊な状況ですね… ( 数字が等幅ではない、ということはそれ以外の文字も等幅ではないのでしょうし… )
メンテ
Re: 数字の等幅ライニングの設定 ( No.16 )
名前:was-blue.0793 日時:2020/01/04 21:07

>>管理人さん 500文字以上の文字列のうち数字だけ等幅化したい……というのは極端な例ですが(仮にULONGLONG型の最大値を描画したとしても20桁)、 以前数字だけ等幅化する実装を行った際、数字以外の文字が混ざると異常な描画結果となる問題が発生したということがあり、 もしDXフォントファイル側が持つグリフ画像自体に最初から空白が入っていれば特に複雑な処理をせずとも数字等幅化を実現できるのではないか……と考えました。 私が考えていたのは「DXフォントファイルに格納するグリフ画像自体を操作し空白を入れる」という実装なのですが、その実装でも変更しなければならない箇所が多いなど、 コストが大きい変更となってしまうのでしょうか? もし単純に左右に均等に空白を入れる実装を行う場合「1」が若干右寄りになる問題しますが(私の実装でも同じ問題が発生しています)、 私としてはこの問題はフォントを使う側が強引に等幅化しようとしているということになるので、この問題はやむを得ないものと考えています。
メンテ
Re: 数字の等幅ライニングの設定 ( No.17 )
名前:管理人 日時:2020/01/05 07:16

> 私が考えていたのは「DXフォントファイルに格納するグリフ画像自体を操作し空白を入れる」という実装なのですが、その実装でも変更しなければならない箇所が多いなど、 > コストが大きい変更となってしまうのでしょうか? 実装のコストもありますが、他にも 1.実用的かどうかが疑問   was-blue.0793さんも仰られていますが、単純に左右に均等に空白を入れるだけでは  バランスが悪く、結局 DrawString で数字毎に座標を調節する必要がありそうです 2.需要が少ない可能性が高い   そもそもプロポーショナルフォントの数字のみを固定幅で描画したい、という方はあまり  居らっしゃらないように感じます   また、仮に居られたとしても 1の理由により、使われない可能性も高いです 3.既存の機能で実現可能   専用の機能を追加しなくても、既存の機能で実装することができ、且つ自前で実装したほうが  微調整も可能なため、1, 2 の理由と合わせると専用の機能を追加する理由が薄くなります などの理由があります 個人的には、以前されたという『数字だけ等幅化する実装を行われた際に発生した描画結果の異常』というのを 調査した方が良いと思います ( 寧ろ、長い文字列で 10FPS を切ってしまったという件も含め、DXライブラリの問題である可能性もあるので 描画結果の異常などの件について詳しくお聞きしたいです… )
メンテ
Re: 数字の等幅ライニングの設定 ( No.18 )
名前:was-blue.0793(解決) 日時:2020/01/05 13:56

>>管理人さん ご指摘通り、プロポーショナルな数字を強引に等幅化するということは実装コストが高い割に需要が薄いかもしれません。 (頻繁に動く数字の幅が変わって見苦しい場合は最初から数字が等幅なフォントを使うでしょうし……) 数字だけ等幅化する実装における描画結果の異常、500文字以上の文字列で異常な重さとなる問題はこのスレッドで提起した話題とは大きく異なる問題となりますので、 検証を行った後、別スレッドで問題提起させていただくこととします。 携帯から投稿しているため実際の検証は後ほど行いますが、取り急ぎこの話題については解決とさせていただきます。 お手数をおかけして申し訳ございませんでした。
メンテ

Page: 1 |

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

   クッキー保存