Richtextbox based custom caching issues

Ok, so I've been working on something for a while, and I've gotten to the point where I'm planning the rendering part of the text.

I can already draw lines of text in two ways; DrawString and TextRenderer.DrawText. I prefer DrawText as the measurement of the text is more accurate when using TextRenderer.Measure text.

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 the characters pressed:

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

      

Now my problem is that I need to be able to set a different font, color and boldness or italic for any selected characters or words at runtime. So I can't just draw the whole line, because then I won't be able to customize the font settings for each character that the user has chosen to change.

So I need to be able to store different font style data for each character and then add it to the list so that I can go through each one and draw each how it should be drawn (IE each char having its own style, etc.) etc.).

This solution works great for me. And since I couldn't find any information on this for months, I am completely stuck.

My main problem is that since I am drawing char to char, I have no idea how far each character should be from the previously drawn character (kerning).

For input elements (textbox), how can we draw the text and allow the user to form part of the word "blue" and the other half of the word to have a different size, color and style, for example, while adhering to proper kerning settings?

How do we know where to draw each character?

People said just restart the whole line at once. But that doesn't solve my original problem. I need to be able to draw each char one by one so that I can store information about that font.

0


source to share


1 answer


Kerning and Character spacing differ, and if you want 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 1 pixel character spacing, no kerning. enter image description here

Image two has kerning applied, but only for three kerning pairs. enter image description here

I tried to clarify the situation by also drawing the result of the personal text measurements. There is also a 1-pixel tiled bitmap as the BackgroundImage panel. (To verify this, you can upload png files!)

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 type designers do it by hand, gazing at the glyphs closely, tweaking the kerning until it's really good.

This is quite expensive and still does not apply to font mixing.

So you may want to either

  • don't use kerning after all. Be sure to use the parameter StringFormat.GenericTypographic

    for both measuring and drawing lines!
  • create a small kerning table for some particularly problematic characters like "L", "T", "W", "V" and "A" ..
  • write some code to create a complete kerning table for all pairs you need, or ..
  • for all couples

To write the code to create a kerning table, you must:

  • Creating a bitmap for each symbol
  • Iterate over all pairs and
  • move the second bitmap to the left until some opaque / black pixels collide.
  • the move should not exceed, say, half the width, otherwise the distance should be reset to 0, because some character pairs will not collide at all and should not have kerning, for example: '^ _' or '.-'

If you want to mix fonts and / or FontStyles, the kerning table key must be expanded to include some identifier for the two matching fonts and styles that the characters have.

+2


source







All Articles