フォントの選択は、とりあえず最も手軽そうなChooseFontコモンダイアログを使用してみました。
ダイアログにパラメータを指定するためのCHOOSEFONT構造体と、選択結果を受け取るためのLOGFONT構造体を用意して、CHOOSEFONT構造体に適当な初期値をセットしたうえでChooseFontダイアログを呼び出します。
設定する初期値はほぼサンプルのままでいいのですが、FlagsにCF_NOVERTFONTSを指定しておくと縦書き (というか横向き) フォントが選択されないので便利です。
また、2回目以降の呼び出しでは前回取得したLOGFONT構造体をそのまま渡して、FlagsにCF_INITLOGFONTSTRUCTを指定すると前回選択した指定でChooseFontダイアログが立ち上がるので、ちょっと便利かもしれません。
ChooseFontダイアログをサンプルのままで使うと、LOGFONT構造体のフォントサイズとしてディスプレイに対応したサイズが設定されてきます。細かく言うと、フォントの高さを示すlfHeight要素には指定されたフォントサイズをディスプレイの解像度に応じて調整した値にマイナス符号をつけたものが設定され、幅を示すlfWidth要素には0が設定されます。
このデータを使用してCreateFontIndirectによりフォントを作成すると、フォントの高さは使用しているフォントに合わせた調整がされます。といっても、現在はほとんどのフォントがTrueTypeないしOpenTypeといったスケーラブルフォントなので、あまり細かいことを気にする必要はありませんが、ビットマップフォントなどを使用している場合にはフォントサイズが指定と異なってびっくりするかもしれません。
また、lfWidthが0の場合はフォントのアスペクト比に応じた幅が使用されるので、長体や平体を使用する場合以外はそのままで問題ないと思います。
長体や平体のフォントを指定したい場合には、SelectObjectでフォントをデバイスコンテキストに設定した後にGetTextMetrixでフォントメトリクスを取得して、得られたTEXTMETRIC構造体のtmHeightとtmAveCharWidthに対してアスペクト比に応じた計算を行い、LOGFONT構造体のlfHeightとlfWidthに設定してCreateFontIndirectを実行することでアスペクト比を変えたフォントを生成することができます。
フォントが指定できればTextOutやDrawTextで文字列が出力できますが、和文と英文で異なるフォントを使用した場合のベースラインの揃え方などは少し研究が必要そうです。
印刷する場合は、PrintDlgで印刷ダイアログを表示し、戻り値に含まれるデバイスコンテキストに対して出力を実行します。
画面への出力との違いは、印刷開始時にStartDocを呼び出し、印刷終了時にEndDocを呼び出すことと、ページの先頭でStartPage、ページの終わりでEndPageを呼び出す点です。
また、ChooseFontで作成したLOGFONT構造体の文字サイズは画面に合わせられているので、印刷時には印刷解像度に合わせた文字サイズの調整が必要です。
文字サイズをサクッと調整する方法が思いつかなかったので、とりあえずはフォントサイズを決め打ちにしてLOGFONT構造体の説明にあった -MulDiv(PointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72) という式でサイズを計算してlfHeightに設定してみましたが、たぶんまともな方法があると思います。
さて、ここで本題です。
PostScriptデータとしてPScript5を使用したプリンタードライバーで印刷を行い、文字がどのようにエンコードされているかを確認しました。
最近、CIDフォントを雑に扱っているために文字化けが起きるといった印刷事故を見かけるようになったので、一度試してみたかったというのが今回のWin32遊びの目的です。
結果から言うと、一部謎を含むもののちゃんとエンコードされていました。
TrueTypeやOpenTypeといったフォントは文字とエンコーディングが分離されていて、個々の文字にはCID (またはGID) と呼ばれる番号が指定されています。
それとは別にCMapと呼ばれる文字コードからCIDへの対応表が文字コードごとに用意されていて、文字コードの違いや縦書き・横書きでの字形の入れ替えなどはCMapで対応することになっています。
最近見かける文字化けはフォントに設定されていたCIDとは異なる番号が文字に設定されている事例でした。
文字が出現した順に1から連番を振っているとか、そういうものです。
プリンターなどはフォントキャッシュを持っていて、フォントキャッシュはCIDで文字を識別するため、文字とCIDの関係が崩れると指定された文字とは別の文字の文字画像をフォントキャッシュから取り出して印字してしまいます。
このため、文字とCIDの関係は変えてはなりません。
手元のPC (Windows 10 バージョン 20H2) に搭載されているPScript5は難しいことをしなければ文字とCIDの関係を変えることはなく、エンコーディングとしてIdentity-Hを指定し、CIDで文字を指定しているようでした。
でも、UnicodeのCMapを登録しているのは謎。
ダイアログにパラメータを指定するためのCHOOSEFONT構造体と、選択結果を受け取るためのLOGFONT構造体を用意して、CHOOSEFONT構造体に適当な初期値をセットしたうえでChooseFontダイアログを呼び出します。
設定する初期値はほぼサンプルのままでいいのですが、FlagsにCF_NOVERTFONTSを指定しておくと縦書き (というか横向き) フォントが選択されないので便利です。
また、2回目以降の呼び出しでは前回取得したLOGFONT構造体をそのまま渡して、FlagsにCF_INITLOGFONTSTRUCTを指定すると前回選択した指定でChooseFontダイアログが立ち上がるので、ちょっと便利かもしれません。
ChooseFontダイアログをサンプルのままで使うと、LOGFONT構造体のフォントサイズとしてディスプレイに対応したサイズが設定されてきます。細かく言うと、フォントの高さを示すlfHeight要素には指定されたフォントサイズをディスプレイの解像度に応じて調整した値にマイナス符号をつけたものが設定され、幅を示すlfWidth要素には0が設定されます。
このデータを使用してCreateFontIndirectによりフォントを作成すると、フォントの高さは使用しているフォントに合わせた調整がされます。といっても、現在はほとんどのフォントがTrueTypeないしOpenTypeといったスケーラブルフォントなので、あまり細かいことを気にする必要はありませんが、ビットマップフォントなどを使用している場合にはフォントサイズが指定と異なってびっくりするかもしれません。
また、lfWidthが0の場合はフォントのアスペクト比に応じた幅が使用されるので、長体や平体を使用する場合以外はそのままで問題ないと思います。
長体や平体のフォントを指定したい場合には、SelectObjectでフォントをデバイスコンテキストに設定した後にGetTextMetrixでフォントメトリクスを取得して、得られたTEXTMETRIC構造体のtmHeightとtmAveCharWidthに対してアスペクト比に応じた計算を行い、LOGFONT構造体のlfHeightとlfWidthに設定してCreateFontIndirectを実行することでアスペクト比を変えたフォントを生成することができます。
フォントが指定できればTextOutやDrawTextで文字列が出力できますが、和文と英文で異なるフォントを使用した場合のベースラインの揃え方などは少し研究が必要そうです。
印刷する場合は、PrintDlgで印刷ダイアログを表示し、戻り値に含まれるデバイスコンテキストに対して出力を実行します。
画面への出力との違いは、印刷開始時にStartDocを呼び出し、印刷終了時にEndDocを呼び出すことと、ページの先頭でStartPage、ページの終わりでEndPageを呼び出す点です。
また、ChooseFontで作成したLOGFONT構造体の文字サイズは画面に合わせられているので、印刷時には印刷解像度に合わせた文字サイズの調整が必要です。
文字サイズをサクッと調整する方法が思いつかなかったので、とりあえずはフォントサイズを決め打ちにしてLOGFONT構造体の説明にあった -MulDiv(PointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72) という式でサイズを計算してlfHeightに設定してみましたが、たぶんまともな方法があると思います。
さて、ここで本題です。
PostScriptデータとしてPScript5を使用したプリンタードライバーで印刷を行い、文字がどのようにエンコードされているかを確認しました。
最近、CIDフォントを雑に扱っているために文字化けが起きるといった印刷事故を見かけるようになったので、一度試してみたかったというのが今回のWin32遊びの目的です。
結果から言うと、一部謎を含むもののちゃんとエンコードされていました。
TrueTypeやOpenTypeといったフォントは文字とエンコーディングが分離されていて、個々の文字にはCID (またはGID) と呼ばれる番号が指定されています。
それとは別にCMapと呼ばれる文字コードからCIDへの対応表が文字コードごとに用意されていて、文字コードの違いや縦書き・横書きでの字形の入れ替えなどはCMapで対応することになっています。
最近見かける文字化けはフォントに設定されていたCIDとは異なる番号が文字に設定されている事例でした。
文字が出現した順に1から連番を振っているとか、そういうものです。
プリンターなどはフォントキャッシュを持っていて、フォントキャッシュはCIDで文字を識別するため、文字とCIDの関係が崩れると指定された文字とは別の文字の文字画像をフォントキャッシュから取り出して印字してしまいます。
このため、文字とCIDの関係は変えてはなりません。
手元のPC (Windows 10 バージョン 20H2) に搭載されているPScript5は難しいことをしなければ文字とCIDの関係を変えることはなく、エンコーディングとしてIdentity-Hを指定し、CIDで文字を指定しているようでした。
でも、UnicodeのCMapを登録しているのは謎。
※コメント投稿者のブログIDはブログ作成者のみに通知されます