自定义richtextbox控制字距调整问题

时间:2015-03-12 19:17:40

标签: c# .net winforms gdi kerning

好的,所以我已经做了一段时间的事情,我已经到了计划文本渲染部分的地步。

我已经可以通过两种方式绘制文字串; DrawString和TextRenderer.DrawText。我更喜欢DrawText,因为在使用TextRenderer.Measure文本时测量文本更准确。

我有一个班级:

public class Character 
{
public string character {get; set; } 
public Font font {get; set; }
public Point position {get; set; }
} 

按下所有字符的列表:

public List<Character> chars = new List<Character>();

现在我的问题是我需要能够在运行时为任何给定的选定字符或单词设置不同的字体和颜色以及粗体或斜体。所以我不能只绘制整个字符串,因为那时我无法为用户选择更改的每个字符设置单独的字体设置。

所以我需要能够为每个字符存储不同的字体样式信息,然后将它们全部添加到列表中,这样我就可以通过每个字符并绘制每个字符,因为它应该被绘制(IE每个字符都有自己的字符风格等)。

此解决方案适用于我。而且由于我几个月来一直无法找到任何关于此的信息,我完全陷入困境。

我的主要问题是因为我正在通过char绘制char,我不知道每个角色与先前绘制的角色(字距调整)相距多远。

对于输入(文本框)控件,我们如何自定义绘制文本并允许用户将单词的一部分设为蓝色,而另一半的单词则具有不同的大小,颜色和样式,例如,坚持适当的字距调整设置?

我们如何知道每个角色的绘制位置?

人们说只要一次重启整个字符串。但这并不能解决我最初的问题。我需要能够逐个绘制每个字符,这样我就可以保存它的字体信息。

1 个答案:

答案 0 :(得分:2)

字距字符间距不同,如果您希望完全控制代码打印的内容,则可能需要同时实现这些内容。

让我们先看一个示例输出:

图像一显示直接输出,额外字符间距为1像素,无字距。 enter image description here

图片二应用了一些字距调整,但仅适用于三个字距调整对。 enter image description here

我还尝试通过绘制字符文本测量结果来使事情变得更清晰。还有一个平铺的1像素栅格作为面板BackgroundImage。 (为了更好地查看它,您可能需要下载png文件!)

private void panel2_Paint(object sender, PaintEventArgs e)
{
   string fullText = "Text;1/2' LTA";
   StringFormat strgfmt = StringFormat.GenericTypographic;
   Font font = new Font("Times", 60f, FontStyle.Regular);
   float x = 0f;
   using (SolidBrush brush = new SolidBrush(Color.FromArgb(127, 0, 127, 127)))
   {
        for (int i = 0; i < fullText.Length; i++)
        {
            string text = fullText.Substring(i, 1);
            SizeF sf = e.Graphics.MeasureString(text, font, 9999, strgfmt );
            e.Graphics.FillRectangle(brush, new RectangleF(new PointF(x, 0f), sf));
            e.Graphics.DrawString(text, font, Brushes.Black, x, 0, strgfmt );
            x += sf.Width + 1;  // character spacing = +1

            //if (i < fullText.Length - 1) doKerning(fullText.Substring(i, 2), ref x);
        }
   }
}

void doKerning(string c12, ref float x)
{
    if (smallKerningTable.ContainsKey(c12)) x -= smallKerningTable[c12];
}

Dictionary<string, float> smallKerningTable = new Dictionary<string, float>();

void initKerningTable()
{
    smallKerningTable.Add("Te", 7f);
    smallKerningTable.Add("LT", 8f);
    smallKerningTable.Add("TA", 11f);
    //..
}

这是创建背景的方式:

public Form1()
{
   InitializeComponent(); 
   Bitmap bmpCheck2 = new Bitmap(2, 2);   
   bmpCheck2.SetPixel(0, 0, Color.FromArgb(127, 127, 127, 0));
   panel2.BackgroundImage = bmpCheck2;
   panel2.BackgroundImageLayout = ImageLayout.Tile;
   //..
 }

如果要使用字距调整,则需要构建更长的字距调整表。

在现实生活中,印刷工作者和字体设计师会手动完成,仔细查看字形,调整字距,直到看起来真的很好。

这相当昂贵,但仍然不包括字体混合。

所以你可能想要

  • 毕竟不使用字距调整。 请务必使用 StringFormat.GenericTypographic 选项进行测量和绘制字符串!
  • 为一些特别有问题的字符创建一个小的字距调整表,例如'L','T','W',“V”和“A”..
  • 编写代码,为您需要的所有对创建一个完整的字距调整表。
  • 适用于所有对

要编写代码以创建字距调整表,您将:

  • 为每个字符创建一个位图
  • 迭代所有对和
  • 将第二个位图向左移动,直到某些非透明/黑色像素发生碰撞。
  • 移动不应该比宽度的一半更远,否则距离应该重置为0,因为一些字符对根本不会发生碰撞并且不应该有任何字距,例如:'^ _'或'.-'

如果你想混合字体和/或FontStyles,那么必须扩展字距调整表的键,以包含字符所具有的两个相应字体和样式的ID。