Search code examples
c#.netgraphicsfontsdrawstring

C# Position font in middle of rectangle with the biggest fitting size


I'm trying to generate a font-map using C#'s Graphics class.

The characters are supposed to be perfectly in the middle of their rectangle in order to use them afterwards. Secondly, I want to use the biggest font-size with all characters fitting into their box.

Example of such a font-map

This is my attempt at doing so. However, when I run this, the characters are not in the middle of their rectangle and it seems like they're rather attached to the upper-left corner of it, considering they're pretty jump when you go trough the different maps.

foreach (String FontName in DataHandler.GetFonts())
            {
                foreach (FontStyle Style in Enum.GetValues(typeof(FontStyle)))
                {
                    try
                    {
                        Bitmap map = new Bitmap(585, 559);
                        Graphics g = Graphics.FromImage(map);

                        for (int i = 0; i < charOrder.Length; i++)
                        {
                            string character = charOrder.Substring(i, 1);
                            g.DrawString(character, new Font(FontName, 30 / new Font(FontName, 20).FontFamily.GetEmHeight(Style), Style), new SolidBrush(myColor), new RectangleF(new PointF((i % charactersPerRow) * 40, ((i - (i % charactersPerRow)) / charactersPerRow) * 80), new SizeF(40, 80)));
                        }
                        map.Save(OutputPath + "\\" + Style.ToString() + "_" + FontName + ".png");
                    }
                    catch (Exception)
                    {

                    }
                }
            }

How would I make the characters fit perfectly into in the middle of their rectangle?

EDIT: All characters of one font would have to use the same font-size, obviously.


Solution

  • Here's what I came up with...

            int charactersPerRow = 14;
            string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-=~!@#$%^&*()_+,./;'[]\\<>?:\"{}|";
            int rows = (int)Math.Ceiling((decimal)chars.Length / (decimal)charactersPerRow);
    
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
    
            foreach (String FontName in DataHandler.GetFonts())
            {
                foreach (FontStyle Style in Enum.GetValues(typeof(FontStyle)))
                {
                    try
                    {
                        Bitmap map = new Bitmap(585, 559);
                        using (Graphics g = Graphics.FromImage(map))
                        {
                            // each char must fit into this size:
                            SizeF szF = new SizeF(map.Width / charactersPerRow, map.Height / rows);
    
                            // fallback font and size
                            int fntSize = 8;
                            Font fnt = new Font(FontName, fntSize, Style);
    
                            // figure out the largest font size that will fit into "szF" above:
                            bool smaller = true;
                            while (smaller)
                            {
                                Font newFnt = new Font(FontName, fntSize, Style);
                                for (int i = 0; i < chars.Length; i++)
                                {
                                    SizeF charSzF = g.MeasureString(chars[i].ToString(), newFnt);
                                    if (charSzF.Width > szF.Width || charSzF.Height > szF.Height)
                                    {
                                        smaller = false;
                                        break;
                                    }
                                }
                                if (smaller)
                                {
                                    if (fnt != null)
                                    {
                                        fnt.Dispose();
                                    }
                                    fnt = newFnt;
                                    fntSize++;
                                }
                            }
    
                            // draw each char at the appropriate location:
                            using (SolidBrush brsh = new SolidBrush(myColor))
                            {
                                for (int i = 0; i < chars.Length; i++)
                                {
                                    PointF ptF = new PointF(
                                        (float)(i % charactersPerRow) / (float)charactersPerRow * map.Width,
                                        ((float)((int)(i / charactersPerRow)) / (float)rows) * map.Height);
                                    g.DrawString(chars[i].ToString(), fnt, brsh, new RectangleF(ptF, szF), sf);
                                }
                            }
                            map.Save(OutputPath + "\\" + Style.ToString() + "_" + FontName + ".png");
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            }