33

テキストをビットマップにレンダリングするとき、不透明でないアルファを含む領域の上にテキストをレンダリングすると、テキストの見栄えが非常に悪くなります。下にあるピクセルがより透明になるにつれて、問題は次第に悪化します。推測する必要がある場合は、下にあるピクセルが透明な場合、テキスト レンダラーはアンチエイリアス処理された「灰色」のピクセルを黒一色として描画します。

ここにいくつかのスクリーンショットがあります:

透明なピクセルの上に描画されるテキスト:

代替テキスト

半透明のピクセルの上に描画されるテキスト:

代替テキスト

不透明なピクセルに描画されるテキスト:

代替テキスト

テキストのレンダリングに使用されるコードは次のとおりです。

g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawString("Press the spacebar", Font, Brushes.Black, textLeft, textTop);
4

4 に答える 4

37

この問題を回避するために使用したオプションは次のとおりです。

Graphics graphics = new Graphics();
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;

TextRenderingHint には他にも便利なオプションがいくつかあります

それが役に立てば幸い

于 2011-08-16T13:27:52.867 に答える
20

これには非常に簡単な答えがあります...

g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit

テキストをレンダリングする前にこれを設定すると、テキストが明確になります。さらに、このメソッドはより多くのフォント サイズをサポートします (デフォルトは最大サイズ 56 までです)。

この投稿を読んでくれてありがとう。

于 2014-08-02T17:07:02.683 に答える
14

最初の出力は、黒の背景に黒のテキストを描画したときに得られるもので、おそらく Color.Transparent です。2枚目はほぼ黒背景で描きました。3つ目は、表示されているのと同じ背景で描かれました。

背景が透明な場合、アンチエイリアスは機能しません。アンチエイリアシング ピクセルに使用される色は、テキストが異なる背景で表示される場合、文字の形状を背景にブレンドしません。これらのピクセルは非常に目立つようになり、テキストの見栄えが非常に悪くなります。

SmoothingMode はテキスト出力に影響しないことに注意してください。低品質の TextRenderingHint と、アルファがゼロの灰色がかった背景色を使用すると、見た目が少し悪くなります。TextRenderingHint.SingleBitPerPixelGridFit のみが、すべてのアンチエイリアスの問題を回避します。

これを完全に修正するのは非常に困難です。Vista のウィンドウ タイトル バーのガラス効果は、非常に微妙なシェーディングを使用して、テキストに明確な背景色を与えます。実際に見るには、SysInternals の ZoomIt ツールが必要です。ゼロ以外の iGlowSize を持つ DrawThemeTextEx() 関数。

于 2010-06-07T17:16:53.077 に答える
2

デフォルトで GDI+ よりもアンチエイリアシングを維持するものを探している場合はGraphics.Clear、クロマ キーを使用して呼び出し、結果として生じるクロマ アーティファクトを手動で削除できます。(なぜ DrawString はとてもくだらないように見えるのですか?と見苦しいテキストの問題を参照してください。)

最終的に同様の問題を解決した方法は次のとおりです。

static Bitmap TextToBitmap(string text, Font font, Color foregroundColor)
{
  SizeF textSize;

  using ( var g = Graphics.FromHwndInternal(IntPtr.Zero) )
    textSize = g.MeasureString(text, font);

  var image = new Bitmap((int)Math.Ceiling(textSize.Width), (int)Math.Ceiling(textSize.Height));
  var brush = new SolidBrush(foregroundColor);

  using ( var g = Graphics.FromImage(image) )
  {
    g.Clear(Color.Magenta);
    g.SmoothingMode = SmoothingMode.AntiAlias;
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
    g.DrawString(text, font, brush, 0, 0);
    g.Flush();
  }

  image.MakeTransparent(Color.Magenta);

  // The image now has a transparent background, but around each letter are antialiasing artifacts still keyed to magenta.  We need to remove those.
  RemoveChroma(image, foregroundColor, Color.Magenta);
  return image;
}

static unsafe void RemoveChroma(Bitmap image, Color foregroundColor, Color chroma)
{
  if (image == null) throw new ArgumentNullException("image");
  BitmapData data = null;

  try
  {
    data = image.LockBits(new Rectangle(Point.Empty, image.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

    for ( int y = data.Height - 1; y >= 0; --y )
    {
      int* row = (int*)(data.Scan0 + (y * data.Stride));
      for ( int x = data.Width - 1; x >= 0; --x )
      {
        if ( row[x] == 0 ) continue;
        Color pixel = Color.FromArgb(row[x]);

        if ( (pixel != foregroundColor) &&
             ((pixel.B >= foregroundColor.B) && (pixel.B <= chroma.B)) &&
             ((pixel.G >= foregroundColor.G) && (pixel.G <= chroma.G)) &&
             ((pixel.R >= foregroundColor.R) && (pixel.R <= chroma.R)) )
        {
          row[x] = Color.FromArgb(
            255 - ((int)
              ((Math.Abs(pixel.B - foregroundColor.B) +
                Math.Abs(pixel.G - foregroundColor.G) +
                Math.Abs(pixel.R - foregroundColor.R)) / 3)),
            foregroundColor).ToArgb();
        }
      }
    }
  }
  finally
  {
    if (data != null) image.UnlockBits(data);
  }
}

GDI/GDI+ がこれをまだ行っていないのは残念ですが、それは理にかなっていると思いませんか? :)

コンテキストを使用できない場合は、 andでunsafe同じロジックを簡単に使用できますが、大幅に遅くなります。Bitmap.GetPixelBitmap.SetPixel

于 2014-08-01T22:23:28.657 に答える