使用Graphics类在C#中精确定位文本

时间:2013-11-19 17:37:27

标签: c# graphics

我制作了一个允许我制作字体贴图纹理的程序。结果图片上的大多数字符都会正确显示,除了一些带来一些问题的例外情况,如下面的放大屏幕截图所示:(使用的字体是Arial NarrowFontStyles.Bold

The result

正如你所看到的,一些消除锯齿的像素已经以某种方式进入了字符“i”的块中,这对我正在使用的引擎来说是不可接受的。

我正在使用以下代码呈现字符:

using (Graphics g = Graphics.FromImage(bmp)) {
  g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;

  Font font = new Font(FontFamily.Families[listFonts.SelectedIndex],
    (float)numSize.Value, checkBold.Checked ? FontStyle.Bold : FontStyle.Regular);

  Size cellSize = GetCellSize(g, textCharSet.Text, font);
  sizeCellSize = cellSize;

  labelCellSize.Text = cellSize.Width + ", " + cellSize.Height;

  int iColumn = 0;
  int iRow = 0;

  string strText = textCharSet.Text;

  for (int i = 0; i < strText.Length; i++) {
    char c = strText[i];

    // ignore carriage returns
    if (c == '\r') {
      continue;
    }

    // handle newline
    if (c == '\n') {
      iColumn = 0;
      iRow++;
      continue;
    }

    // get single character size
    SizeF singleCharSize = g.MeasureString("" + c, font);

    // get shadow values
    int iShadowX = (int)numShadowX.Value;
    int iShadowY = (int)numShadowY.Value;

    // render cell preview
    if (bPreview) {
      g.FillRectangle(i % 2 == 0 ? Brushes.DarkMagenta : Brushes.Fuchsia,
        new Rectangle(iColumn * cellSize.Width, iRow * cellSize.Height, cellSize.Width, cellSize.Height));
    }

    // render shadow of character if needed
    if (checkShadow.Checked && (iShadowX != 0 || iShadowY != 0)) {
      g.DrawString("" + c, font, Brushes.Black, new PointF(
        iColumn * cellSize.Width + Math.Max(0, iShadowX),
        iRow * cellSize.Height + Math.Max(0, iShadowY)), StringFormat.GenericTypographic);
    }

    // render character
    g.DrawString("" + c, font, Brushes.White, new PointF(
      iColumn * cellSize.Width + -Math.Min(0, iShadowX),
      iRow * cellSize.Height + -Math.Min(0, iShadowY)), StringFormat.GenericTypographic);

    iColumn++;
  }
}

我之前已经设置TextRenderingHint来解决一些问题,但它似乎无法解决所有这些问题。

为什么j部分呈现在i块内,以及如何在保持抗锯齿的同时防止这种情况发生?

2 个答案:

答案 0 :(得分:2)

尝试使用GetCharABCWidths,它将为您提供所需的尺寸。查看B间距,它给出了字形黑色部分的宽度。

http://msdn.microsoft.com/en-us/library/windows/desktop/dd144857(v=vs.85).aspx

您也可以尝试使用GetGlyphOutline和GlyphMetrics结构来获取字形的黑框区域。

是的,尤其是在GetGlyphOutline / GlyphMetrics选项中会考虑消除锯齿,IIRC GetCharABCWidths也会考虑到这一点。

(道歉,我升级到IE 11,由于某种原因不能在这个网站上使用JavaScript ......)

答案 1 :(得分:2)

我的建议是为每个字形创建一个大于您需要的区域作为单独的图形对象,然后将字形渲染到目标图形对象的中心。您可以使用MeasureString,然后在对象周围添加几个像素的缓冲区值。

完成此操作后,您需要找到渲染字形消除锯齿像素的范围,因此我假设所有像素都不具有零alpha值。找到这个后,您可以计算目标中的“已使用”区域,并将其渲染到所需位置的主图形对象上。

我无法给你代码,因为我对.NET中的Graphics对象没有多少经验