7

私の質問は、Windows 7 で正しく動作するためにフォント処理をどのように変更する必要があるかということです。以前は有効だったが、もはや有効ではないという仮定を立てたことは確かです。しかし、私はどこから探し始めればいいのかさえわかりません! 誰かが助けてくれることを祈っています!私が理解している詳細は次のとおりです (Microsoft Windows Developers フォーラムにもこの質問を投稿しましたが、回答はありません)。

はい、私は時代遅れです (まあ、私はまだプレーン C で WIN32 コードを書いています!) ウィンドウのクライアント領域内でさらに古い DOS 画面 I/O ライブラリを模倣する 10 年前の DLL を作成しました。言うまでもなく、固定幅フォントしか使用できません。DLL を使用する一部のプログラムを Windows 7 に移行すると、固定幅の TRUE TYPE フォントを使用すると奇妙なちらつきが発生します (ビットマップ フォントは引き続き完全に動作します)。で書かれた単一の文字ExtTextOutが本来よりも幅が広いことに注意してください。3 つの異なる方法で測定値を確認しました ( GetTextExtentPoint32132 文字の文字列を使用して 132 で除算する方法、呼び出して 256 文字すべてGetTextMetricsを使用する方法GetCharABCWidths)、フォントが同じ幅であることにすべて同意しました。しかしExtTextOutフォント幅よりも 1 ピクセルまたは 2 ピクセル広い背景の四角形をレンダリングしています。パラメータで指定された位置の 1 ピクセルか 2 ピクセル左からバックグラウンド レンダリングを開始するか [次のように呼びます ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL )。 Windows 7 のビットマップ フォント -- しかし、Windows 7 では固定幅の True Type フォントでは正しく動作しなくなりました。

私が何をする必要があるのか​​ 理解していない人のために、方眼紙に正方形ごとに1文字を書くことを想像してみてください. すべての正方形は同じフォントを使用していますが、前景色や背景色が異なる場合があります。テキストの配置を使用しTA_TOP|TA_LEFTます。これは最も単純で、一貫して適用される配置は固定幅フォントでも機能するはずだからです。

私が見ているのは、ExtTextOut が、RECT *パラメーターで指定したよりも大きな背景の四角形を放出していることです。私が提供している四角形は、報告されたフォントのサイズから作成されているため、これは決して起こらないはずです。また、Windows XP 以前では発生せず、Windows 7 のビットマップ (つまり .FON) フォントでは発生しません。また。しかし、これは Windows 7 の固定幅 TrueType フォントで常に発生します。これは、Windows 2000、Windows XP、および Windows 7 (32 & 64) で実行されているまったく同じ EXECUTABLE で発生します。Windows 7 にはバグがあると簡単に言いたいのですが、私は、Windows でのフォント処理について私が立てたいくつかの基本的な仮定が、もはや真実ではないと信じる傾向があります (Windows 用のソフトウェアを 20 年間作成した後)。

しかし、それが何であるかを発見する方法や場所がわかりません! 助けてください!

--- 修正 ---

興味のある人のために、私はバグと考えているものを回避することができました-反対のドキュメントを見つけるまで。私の回避策は、ライブラリに 2 つの変更を加えることです。

  1. GetTextExtentPoint32()からのデータではなく、「X」から返されたサイズを使用しTEXTMETRICSます。
  2. すべての呼び出しにETO_CLIPPINGフラグを含めます。ExtTextOut()

以前は、tmHeight+tmExternalLeading文書化されているように、連続するテキスト行の上部の間のピクセル数に使用していました。)から返される size.cy の値GetTextExtentPoint32(は同じではなく、より正確に見えることがわかりました。私が見つけた最悪の例は、OCRB True Type フォントでした。作成した OCRB フォントのデバッガーで見たものを次に示します (システム フォント選択ダイアログを使用)。

ocrbtm.tmHeight          = 11
ocrbtm.tmExternalLeading =  7

ocrbsize.cy = 11

そのため、まだ発見していない何らかの理由で、Windows は OCRB フォントに定義された外部先行値を無視しています。TM の代わりにサイズの値を使用すると、きれいできちんとした密集したテキストが得られます。これはまさに私が望んでいたことです。

四角形を 1 文字の寸法に正確に設定し、背景を塗りつぶす (そして前のセルの内容を上書きする) ために使用しているため、このETO_CLIPPINGフラグは必要ありません。ETO_OPAQUEサイズ、テキスト メトリック、または ABC 幅のいずれかが示します。少なくとも、これまでに見つけたすべてのドキュメントに基づいて、これは真実です。

HEIGHTの問題は長い間存在していたと思いますが、Windows 7でソフトウェアを実行するまで残りは不要でした.これを私の質問に追加して、私が明らかに理解していないことを誰かが説明できるかどうかを確認します.

-- 修正 2 --

1: 私が見つけることができるすべてのドキュメントはtmHeight+tmExternalLeading、単一行のテキストを生成する必要があると述べています。限目。しかし、それは常に正しいとは限らず、Windows が によって返されることがあるさまざまな値をどのように決定するかを示すドキュメントを見つけることができませんGetTextExtentPoint32()

2: Win7 (Vista の可能性あり) では、本来ExtTextOutよりも少し多くの背景を塗りつぶし始めました (右側にいくつかの余分なピクセルを追加することにより)。ただし、True Type フォントが選択されている場合のみです。四角形が文字の予想サイズの2 倍(両方の寸法) であってもこれを行います。 :1 の倍率であり、これはバグのようです。ビットマップ (.FON) フォントではなく真のタイプにのみ影響するという事実も、スケーリングを除外しているようです (存在しない限り) 。Windows はテキストの一部だけでなく、すべてのテキストをスケーリングしようとするためです。また、[カスタム DPI 設定] ダイアログに [Windows XP スタイルの DPI スケーリングを使用する] という灰色の (チェックされている) 設定があります。最後に、この問題全体は、Aero またはその他の Win7 ネイティブ テーマではなく、Windows クラシック テーマで実行した結果である可能性があります。

-- 修正 3 --

SetProcessDPIAware() を呼び出すだけでは、私が抱えている問題には影響しません。私の問題は 100% DPI 設定 (スケール 1:1) で発生するため、問題DPI 関連である場合、DPI 仮想化のバグを発見したに違いありません。これは、Microsoft がこの機能を次のように説明しているためです。

この機能は、あたかも 96 DPI で実行されているかのように、"仮想化された" システム メトリックと UI 要素をアプリケーションに提供することによって機能します。その後、アプリケーションは 96 DPI のオフスクリーン サーフェスにレンダリングされ、Desktop Windows Manager は結果のアプリケーション ウィンドウを DPI 設定に一致するようにスケーリングします。

私の設定はすべて 100% のスケーリングであることを示しており、カスタム設定ボックスを見ると、それが 96 DPI であることを明確に示しています。つまり、96 DPI から 96 DPI への DPI 仮想化が固定幅 True Type フォントで機能しない場合、Windows に問題がありますよね? または、DPI バーチャライザーを正しく動作させるために呼び出す (または呼び出しを停止する) 必要がある関数はありますか?

想定されるスケーリングの問題が、当初考えていたほど実際にフォントのサイズと関係があるかどうかはまだ確信が持てません。これは、テキスト文字が出力されるのではなく、背景の四角形が塗りつぶされるという問題が発生しているためです。ExtTextOut()フォントが True Type の場合、背景の四角形が少し拡大されます。また、Windows クラシック テーマまたは標準の Windows Aero テーマのどちらを使用しても、この問題が発生することも確認しました。次に、他の人が実験できるように、単純化された例を作成します。

-- 修正 4 --

私が見ているもの (および私が行っていること) を示す最小限のデモ プログラムを作成しました。Visual Studio 2010 プロジェクト/ソースは、http: //www.svalli.com/files/fwtt.7z からダウンロードできます。 -- マルウェアを拡散する危険を冒したくないので、意図的に実行可能ファイルを含めませんでした。プログラムは、固定幅フォントを選択し、2 つの 5x5 文字グリッドをクライアント領域に書き込みます。1 つはサイズを使用して作成され、もう 1 つはGetTextExtentPoint32サイズを使用して作成されます。TEXTMETRICMicrosoft によって文書化されたサイズ。グリッドは黒と白の市松模様で、赤地に黄色の文字が最後に中央に書かれ、オーバーラップ効果を示しています (はっきりと表示するには、ズーム ユーティリティが必要な場合があります)。プログラムは、すぐ下の 5 つの X で始まる文字列も描画します。同じ左オフセットから始まるグリッドは、個々の文字を配置する方法の比較として使用されます (文字列を一致させます)。メニューでは、クリッピングのオン/オフを切り替えたりExtTextOut、他のフォントを選択したりできます。また、起動時にdpiawareプログラムを呼び出すコマンド ライン オプション (大文字と小文字を区別)SetProcessDPIAware()もあり、その呼び出しの効果も評価できます。

これを作成してから、正しい背景の四角形を塗りつぶしていることを学びましたExtTextOutが、不透明な背景でレンダリングされているキャラクターは、本来よりも幅が広く、描画を開始するように指示された場所から開始することさえできない可能性がありますExtTextOut! ExtTextOut最終的に文字間隔が文字列全体をレンダリングしたときに得られるものと一致するため、「あるべき」と言いました。オーバーラップは、指定された長方形の片側または両側にあるようです。たとえば、OCRB は文字セルの左側と右側の両方に余分なピクセルを追加しますが、私が確認した他の True Type フォントは右側に 2 ピクセルを追加します。縁。

私は本当にこれを「正しい」方法でやりたいと思っていますが、私が間違っていることや欠けていることを示すドキュメントが見つかりません。おそらく、100% 以外の縮尺での DPI Aware の何かが欠けていると思いますが、それ以外の場合は困惑しています。

-- 修正 5 --

少し困惑が少ない... 問題は ClearType が原因です。ClearType をオフにすると、すべてのフォントが再び機能するようになりました。XP で ClearType をオンにすると、同じ問題が発生します。どうやら ClearType は (誰かがそれを検出する方法を教えてくれるまで) 静かに (誰かがそれを検出する方法を教えてくれるまで) 文字を水平方向に数ピクセル引き延ばすことができるようです。

この問題を回避する唯一の方法はクリッピングですか?

-- 修正 6 --

上記のクリッピングの質問に対する部分的な回答: 新しいフォントを作成するとき、次のことを行います (疑似コードで):

CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
   if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
        lfQuality = NONANTIALIASED_QUALITY
        DeleteObject( font )
        CreateFontIndirect

クリッピングを有効にしなくても、これはほとんどの場合、使用しているフォント サイズで機能しますが、文字セルの右 (または左) に余分なピクセルをレンダリングするものをいくつか見つけました。幸いなことに、これらはインターネット上で見つかったフリー フォントのように見えるため、全体的な品質はプロのフォント ファウンドリの基準を下回っている可能性があります。

誰かがより良い答えを見つけることができれば、私は本当に、本当にそれを聞くのが大好きです! それまでは、これでいいと思います。ここまで読んでくれてありがとう!

4

1 に答える 1

4

コードが高 DPI 対応であることを確認してから、プロセスが DPI 対応であることを OS に伝えます

DPI に対応していることを OS に伝えないと、一部の測定関数が嘘をつき、ディスプレイの DPI が実際には 96 dpi であるという仮定に基づいて数値を表示します。一方、描画関数は反対方向にスケーリングしようとします。単純な高レベルの描画の場合、このアプローチは一般的に機能します (ただし、テキストがぼやけてしまうことがよくあります)。小さな測定値と個々の文字の正確な配置では、これにより、フォント サイズの不一致などにつながる丸めの問題が発生することがよくあります。この動作は、Windows Vista で導入されました。

Visual Studio 2010 以降では、構文ハイライターがテキストに色を付け、単語を入力すると、あちこちで数ピクセルずつシフトするため、常に表示されます。本当に迷惑です。

修正について:

tmExternalLeadingは、テキストの行間にどれだけ余分なスペースを入れるかについて、フォント デザイナーからの推奨にすぎません。MSDN のドキュメントには、通常、「アプリケーションが行間に追加する余分な先行 (スペース) の量」と記載されています。まあ、あなたはアプリケーションなので、「正しいこと」は、自分でテキストを描画しているときに行間に追加することですが、それは本当にあなた次第です. (DrawText のような高レベルの関数が使用すると思われます。

GetTextExtentPoint32(および友人) がsize.cyequal toを返し、 tmHeightignoreを返すことは完全に正しいことtmExternalLeadingです。プログラマーとして、実際にどれだけ使用するかは、最終的にはあなたの選択です。

これは、いくつかの単純な描画コードで確認できます。ゼロ以外の tmExternalLeading を持つフォントを選択します (Arial は私にとってはうまくいきます)。TextOut独自の背景色を使用してテキストを描画します。次に、テキストを測定し、GetTextExtentPoint32返された値に基づいて線を引きます。背景色の四角形が外部の行送りを除外していることがわかります。外部主導はまさにそれです:外部。文字セルの境界内にありません。

  // Draw the sample text with an opaque background.
  assert(::GetMapMode(ps.hdc) == MM_TEXT);
  assert(::GetBkMode(ps.hdc) == OPAQUE);
  assert(::GetTextAlign(ps.hdc) == TA_TOP);
  COLORREF rgbOld = ::SetBkColor(ps.hdc, RGB(0xC0, 0xFF, 0xC0));
  ::TextOutW(ps.hdc, x, y, pszText, cchText);
  ::SetBkColor(ps.hdc, rgbOld);

  // This vertical line at the right side of the text shows that opaque
  // background is exactly the height returned by GetTextExtentPoint32.
  SIZE size = {0};
  if (::GetTextExtentPoint32W(ps.hdc, pszText, cchText, &size)) {
    ::MoveToEx(ps.hdc, x + size.cx, y, NULL);
    ::LineTo(ps.hdc, x + size.cx, y + size.cy);
  }

  // These horizontal lines show the normal line spacing, taking into
  // account tmExternalLeading.
  assert(tm.tmExternalLeading > 0);  // ensure it's an interesting case
  ::MoveToEx(ps.hdc, x, y, NULL);
  ::LineTo(ps.hdc, x + size.cx, y);  // top of this line
  const int yNext = y + tm.tmHeight + tm.tmExternalLeading;
  ::MoveToEx(ps.hdc, x, yNext, NULL);
  ::LineTo(ps.hdc, x + size.cx, yNext);  // top of next line

色付きの四角形の下部と次の行の上部との間のギャップは、常に文字セルの外側にある外部リーディングを表します。

OCR-Bは、銀行機器における信頼性の高い光学式文字認識用に設計されています。一部の OCR アプリケーションでは、(実際のテキストの高さと比較して) 大きな外部行送りを持つことが適切な場合があります。この特定のフォントの場合、おそらく審美的な選択ではありません。

于 2013-02-27T00:40:45.880 に答える