50

レシートを生成し、Graphicsオブジェクトを使用してDrawStringメソッドを呼び出し、必要なテキストを印刷しています。

graphics.DrawString(string, font, brush, widthOfPage / 2F, yPoint, stringformat);

これは、私が必要としていたことに対しては問題なく機能します。私は自分が何を印刷しているのかを常に知っていたので、80mmのレシート用紙に適切に収まるように文字列を手動でトリミングすることができました。次に、これをより柔軟にする機能を追加する必要がありました。ユーザーは、下部に追加される文字列を渡すことができます。

彼らが何を入れようとしているのかわからなかったので、ラップする文字数と文字列自体を取り込む独自のワードラップ関数を作成しました。文字数を調べるために、私は次のようなことをしていました。

float width = document.DefaultPageSettings.PrintableArea.Width;
int max = (int)(width / graphics.MeasureString("a", font).Width);

これで、幅は283を返します。これは、mmで約72です。これは、80mmの用紙の余白を考慮すると意味があります。

しかし、MeasureStringメソッドはCourierNew8ptフォントで10.5を返します。したがって、36〜40であると予想していたものを回避する代わりに、26を取得し、2行のテキストが3〜4に変換されます。

PrintableArea.Widthの単位は1/100インチで、グラフィックスオブジェクトのPageUnitはDisplayです(これは通常、プリンターの場合は1/100インチです)。では、なぜ私は26しか戻ってこないのですか?

4

3 に答える 3

162

WindowsClient.netから:

GDI +は、表示されるすべての文字列の両端に少量(1/6 em)を追加します。この1/6emは、端が張り出したグリフ(斜体の「f」など)を可能にし、GDI+にグリッドフィッティングの拡張を支援するためのわずかな余裕を与えます。

のデフォルトのアクションは、DrawString隣接する実行を表示する際に機能します。

  • まず、デフォルトのStringFormatは、各出力の両端に1/6emを追加します。
  • 第二に、グリッドに取り付けられた幅が設計よりも小さい場合、ストリングは最大emまで収縮することができます。

これらの問題を回避するには:

  • 常に、活版印刷のStringFormat()に基づいてStringFormatをMeasureString渡します。 グラフィックをに設定します。このレンダリング方法では、アンチエイリアシングとサブピクセルグリフポジショニングを使用してグリッドフィッティングの必要性を回避するため、本質的に解像度に依存しません。DrawStringGenericTypographic
    TextRenderingHintTextRenderingHintAntiAlias

.NETでテキストを描画する方法は2つあります。

  • GDI +(graphics.MeasureStringおよびgraphics.DrawString
  • GDI(TextRenderer.MeasureTextおよびTextRenderer.DrawText

Michael Kaplan(rip)の優れたブログSorting It All Outから、.NET 1.1では、すべてがテキストレンダリングにGDI+を使用していました。しかし、いくつかの問題がありました:

  • GDI +のステートレスな性質によって引き起こされるパフォーマンスの問題がいくつかあります。この場合、デバイスコンテキストが設定され、呼び出しごとに元のコンテキストが復元されます。
  • 国際テキストのシェーピングエンジンは、Windows / UniscribeおよびAvalon(Windows Presentation Foundation)で何度も更新されていますが、GDI +では更新されていないため、新しい言語の国際レンダリングサポートの品質は同じではありません。

そのため、 GDI +のテキストレンダリングシステムの使用を停止し、GDIを使用するように.NETFrameworkを変更したいと考えていまし。最初、彼らは単に変更できることを望んでいました。

graphics.DrawString

DrawTextGDI+の代わりに古いAPIを呼び出す。しかし、GDI +とまったく同じように、テキストの折り返しと間隔を一致させることはできませんでした。graphics.DrawStringそのため、彼らはGDI +に電話をかけ続けることを余儀なくされました(互換性の理由。電話をかけていた人々graphics.DrawStringは、突然、テキストが以前のように折り返されていなかったことに気付くでしょう)。

GDIテキストレンダリングをラップするために、新しい静的TextRendererクラスが作成されました。2つの方法があります。

TextRenderer.MeasureText
TextRenderer.DrawText

注: TextRendererはGDIのラッパーgraphics.DrawStringですが、GDI+のラッパーです。


次に、既存のすべての.NETコントロールをどうするかという問題がありました。例:

  • Label
  • Button
  • TextBox

彼らはそれらを使用するために切り替えたいと思っていましたTextRenderer(すなわちGDI)が、彼らは注意しなければなりませんでした。.NET1.1のようにコントロールの描画に依存している人もいるかもしれません。そして、「互換性のあるテキストレンダリング」が生まれました。

デフォルトでは、アプリケーションのコントロールは.NET 1.1の場合と同じように動作します(「互換性があります」)。

次のコマンドを呼び出して、互換モードをオフにします。

Application.SetCompatibleTextRenderingDefault(false);

これにより、アプリケーションがより良く、より速く、より良い国際的なサポートが得られます。総括する:

SetCompatibleTextRenderingDefault(true)  SetCompatibleTextRenderingDefault(false)
=======================================  ========================================
 default                                  opt-in
 bad                                      good
 the one we don't want to use             the one we want to use
 uses GDI+ for text rendering             uses GDI for text rendering
 graphics.MeasureString                   TextRenderer.MeasureText
 graphics.DrawString                      TextRenderer.DrawText
 Behaves same as 1.1                      Behaves *similar* to 1.1
                                          Looks better
                                          Localizes better
                                          Faster

また、GDI+とGDIフォントの描画に使用されるTextRenderingHint対応するLOGFONT品質との間のマッピングに注意することも役立ちます。

TextRenderingHint           mapped by TextRenderer to LOGFONT quality
========================    =========================================================
ClearTypeGridFit            CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6))
AntiAliasGridFit            ANTIALIASED_QUALITY (4)
AntiAlias                   ANTIALIASED_QUALITY (4)
SingleBitPerPixelGridFit    PROOF_QUALITY (2)
SingleBitPerPixel           DRAFT_QUALITY (1)
else (e.g.SystemDefault)    DEFAULT_QUALITY (0)

サンプル

GDI +(graphics.DrawString)とGDI(TextRenderer.DrawText)のテキストレンダリングの比較を次に示します。

GDI +:、GDI::TextRenderingHintClearTypeGridFit_CLEARTYPE_QUALITY

ここに画像の説明を入力してください

GDI +:、GDI::TextRenderingHintAntiAlias_ANTIALIASED_QUALITY

ここに画像の説明を入力してください

GDI +:、GDI:サポートされていませんTextRenderingHintAntiAliasGridFitANTIALIASED_QUALITYを使用します

ここに画像の説明を入力してください

GDI +:、GDI::TextRenderingHintSingleBitPerPixelGridFit_PROOF_QUALITY

ここに画像の説明を入力してください

GDI +:、GDI::TextRenderingHintSingleBitPerPixel_DRAFT_QUALITY

ここに画像の説明を入力してください

DRAFT_QUALITYと同じであるのは奇妙だと思います。PROOF_QUALITYこれはと同じですCLEARTYPE_QUALITY

も参照してください

于 2011-06-19T20:00:18.490 に答える
9

宅配便新サイズ11

サイズ=11のフォント'CourierNew'を作成すると、上の画像のような出力が得られます。高さは下線を除いて14ピクセルであることがわかります。幅は正確に14ピクセルです(各文字に7ピクセル)。

したがって、このフォントは14x14ピクセルをレンダリングします。

ただしTextRenderer.MeasureText()、代わりに21ピクセルの幅を返します。正確な値が必要な場合、これは役に立ちません。

解決策は次のコードです。

Font i_Courier = new Font("Courier New", 11, GraphicsUnit.Pixel);

Win32.SIZE k_Size;
using (Bitmap i_Bmp = new Bitmap(200, 200, PixelFormat.Format24bppRgb))
{
    using (Graphics i_Graph = Graphics.FromImage(i_Bmp))
    {
        IntPtr h_DC = i_Graph.GetHdc();
        IntPtr h_OldFont = Win32.SelectObject(h_DC, i_Courier.ToHfont());

        Win32.GetTextExtentPoint32(h_DC, "Áp", 2, out k_Size);

        Win32.SelectObject(h_DC, h_OldFont);
        i_Graph.ReleaseHdc();
    }
}

k_Sizeには正しいサイズが含まれます:14x14

重要: このコードは、通常のフォントを正しく測定します。イタリックフォント(常に右側にオーバーハングがある)にも正確な値が必要な場合は、この記事に記載されているリンクを読む必要があります:http: //www.codeproject.com/Articles/14915/Width-of- text-in-italic-font

付録: C#でAPI呼び出しを使用したことがない人のために、ここでクラスWin32を作成する方法のヒントを示します。これは完全ではありません。詳細については、http: //www.pinvoke.netをご覧ください。

using System.Runtime.InteropServices;

public class Win32
{       
    [StructLayout(LayoutKind.Sequential)]
    public struct SIZE
    {
        public int cx;
        public int cy;
    }

    [DllImport("Gdi32.dll")]
    public static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out SIZE lpSize);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
}
于 2014-05-08T04:46:07.987 に答える
0

これは、それがどのように機能するかを理解するのに役立つ説明です。そして、各文字の前後に多かれ少なかれスペースを生じさせるもの。

GDIDrawStringConfiguratorアプリ

画面キャプチャ

于 2018-06-12T08:55:43.597 に答える