简体   繁体   English

自定义RichTextBox控件字距调整问题

[英]Custom richtextbox control kerning issues

Okay, so I have been working on something for a little while and I have gotten to the point where I am planning the Text rendering part. 好的,所以我已经做了一段时间了,现在我正在计划文本渲染部分。

I can already draw strings of text in two ways; 我已经可以通过两种方式绘制文本字符串了; DrawString and TextRenderer.DrawText. DrawString和TextRenderer.DrawText。 I prefer DrawText since measuring text is more accurate when using TextRenderer.Measure text. 我更喜欢DrawText,因为使用TextRenderer.Measure文本时测量文本更准确。

I have a class: 我有一堂课:

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

And a list of all characters pressed: 并按一下所有字符的列表:

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

Now my problem is that I need to be able to set a different font and color and boldness or italicization to any given selected characters or words at runtime. 现在我的问题是,我需要能够在运行时为任何给定的选定字符或单词设置不同的字体和颜色,粗体或斜体。 So I can't just draw a whole string because then there'd be no way for me to set individual font settings for each character the user has selected to change. 所以我不能只画一个完整的字符串,因为那样我就无法为用户选择更改的每个字符设置单独的字体设置。

So I need to be able to store different font style info for each character and then add them all to a list so I can kinda go through each one and draw each one as it should be drawn (IE each char having its own style etc). 所以我需要能够为每个字符存储不同的字体样式信息,然后将它们全部添加到列表中,这样我就可以仔细检查每个字符并按应绘制的方式绘制每个字体(即每个字符都有自己的样式,等等) 。

This solution works fine for me. 这个解决方案对我来说很好。 And since I've not been able to find any info about this anywhere for months, I'm totally stuck. 而且由于几个月来我一直找不到任何关于此的信息,所以我完全陷入了困境。

My main problem is that because I am drawing char by char, I have no idea how far apart each character should be from the previously drawn character (kerning). 我的主要问题是,因为我要逐个绘制字符,所以我不知道每个字符与先前绘制的字符(字距)应该相距多远。

For input (text box) controls, how can we custom draw text and allow the user to make a part of a word blue, and the other half of the word a different size and color and style, for example, while still adhering to proper kerning settings? 对于输入(文本框)控件,我们如何自定义绘制文本并允许用户将一个单词的一部分设置为蓝色,而将另一半的单词设置为不同的大小,颜色和样式,例如,同时仍保持正确的外观字距调整设置?

How do we know where to draw each character? 我们如何知道在哪里绘制每个字符?

People have said just keep restarting the whole string at once. 人们说只是保持立即重新启动整个字符串。 But that doesn't solve my initial problem. 但这并不能解决我最初的问题。 I need to be able to draw each char one by one so I can save font info about it. 我需要能够一一绘制每个字符,以便我可以保存有关它的字体信息。

Kerning and Character Spacing are different and if you want to have complete control over what your code prints you may need to implement both. 字距字符间距是不同的,如果要完全控制代码的输出,则可能需要同时实现两者。

Let's look at an example output first : 首先让我们看一个示例输出:

Image one shows direct output with an extra character spacing of 1 pixel, no kerning. 图一显示了直接输出,额外字符间距为1个像素,没有字距调整。 在此处输入图片说明

Image two has some kerning applied, but only for three kerning pairs. 图像二应用了一些字距调整,但仅适用于三个字距调整对。 在此处输入图片说明

I have tried to make things clearer by also drawing the result of the characterwise text measurements. 我还试图通过绘制字符式文本测量结果来使事情更清楚。 Also there is a tiled 1 pixel raster as the panel BackgroundImage. 此外,还有一个平铺的1像素栅格作为面板BackgroundImage。 (To see it better you may want to download the png files!) (为了更好地查看,您可能需要下载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);
    //..
}

This is how the background is created: 这是创建背景的方式:

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;
   //..
 }

If you want to use kerning you will need to build a much longer kerning table. 如果要使用字距调整,则需要构建更长的字距调整表。

In real life typographers and font designers do that manually, looking hard at the glyphs, tweaking the kerning until it looks real good. 在现实生活中,排版人员和字体设计师会手动执行此操作,仔细观察字形,调整字距调整,直到看起来真好。

That is rather expensive and still doesn't cover font mixes. 那是相当昂贵的,并且仍然不包括字体混合。

So you may want to either 所以您可能想要

  • not use kerning after all. 毕竟不要使用字距调整。 Make sure to use the StringFormat.GenericTypographic option both for measuring and for drawing the strings! 确保同时使用 StringFormat.GenericTypographic 选项进行测量和绘制字符串!
  • create a small kerning table for some of the especially problematic characters, like 'L', 'T', 'W', "V' and 'A'.. 为某些特别有问题的字符创建一个小的字距表,例如“ L”,“ T”,“ W”,“ V”和“ A”。
  • write code to create a full kerning table for all pairs you need or.. 编写代码为您需要的所有对创建完整的字距表。
  • for all pairs 对于所有对

To write code to create a kerning table you would: 要编写代码以创建字距表,您需要:

  • Create a Bitmap for each charcter 为每个字符创建一个位图
  • Iterate over all pairs and 遍历所有对
  • move the second bitmap to the left until some non-transparent/ black pixels collide. 向左移动第二个位图,直到某些非透明/黑色像素发生碰撞。
  • the moving should not got further than, say, half of the width, otherwise the distance should be reset to 0, because some character pairs will not collide at all and should not have any kerning, eg: '^_' or '.-' 移动的距离不应超过宽度的一半,否则,距离应重置为0,因为某些字符对根本不会发生冲突并且不应有任何字距调整,例如:'^ _'或'.- '

If you want to mix fonts and /or FontStyles the key to the kerning table would have to be expanded to include some ID of the two respective fonts&styles the characters have.. 如果要混合字体和/或FontStyles,则字距调整表的关键字必须扩展为包括字符具有的两种相应字体和样式的一些ID。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM