2

I try to draw a string (single character) in C# into a Bitmap at an exact position with:

Bitmap bmp = new Bitmap(64, 64); Graphics g = Graphics.FromImage(bmp); g.DrawString("W", font1, new SolidBrush(myColor), new Point(32,32); 

There is so much empty space rendered around a single letter, that I can not guess the "needed" position to draw the character to have it at the correct position at the end.

By now I have the pixel exact dimension of the character (looking at bits in a separately rendered bitmap). But this information is useless, if I cannot draw the character at an exact position (e.g. center or top right corner or ....).

Are there other methods to draw text in C# on a bitmap? Or are there any converting methods to convert the real pixel position in something DrawString needs?

11
  • Are you looking for Graphics.MeasureString/MEasureCharRanges which will calculate the bounding rectangle? Commented Oct 15, 2015 at 12:32
  • Would it help you to measure the string before drawing it? Commented Oct 15, 2015 at 12:32
  • 1
    Well just offset the draw origin by half the glyph width/height Commented Oct 15, 2015 at 13:00
  • 1
    You could copy the pixels from your 'extra' bitmap after you've examined all of the pixels. You could also design your own 'font' and rasterize the characters yourself. Commented Oct 15, 2015 at 13:12
  • 1
    @Konrad - the point that Alex and Corak make, is that once you know the offset between the bounding ("outer") rectangle, and the non blank pixels ("inner rectangle), you can compensate for that offset. However, Corak gave the wrong formula. Given blank widths LM/TM/RM/BM (left/top/right/bottom margin): To position the upper-left corner: pos.X -= LM; pos.Y -= TM. To correct a center placement (assuming you've already adjusted pos to center): pos.X -= (LM-RM)/2; pos.Y -= (TM-BM)/2; Commented Aug 12, 2017 at 16:01

1 Answer 1

5

No need to look at the pixels or start working with your own font..

You can use a GraphicsPath instead of DrawString or TextRenderer, as it will let you know its net bounds rectangle with GraphicsPath.GetBounds() .

When you know it, you can calculate how to move the Graphics object using TranslateTransform:

enter image description here

private void button1_Click(object sender, EventArgs e) { string text = "Y"; // whatever Bitmap bmp = new Bitmap(64, 64); // whatever bmp.SetResolution(96, 96); // whatever float fontSize = 32f; // whatever using ( Graphics g = Graphics.FromImage(bmp)) using ( GraphicsPath GP = new GraphicsPath()) using ( FontFamily fontF = new FontFamily("Arial")) { testPattern(g, bmp.Size); // optional GP.AddString(text, fontF, 0, fontSize, Point.Empty, StringFormat.GenericTypographic); // this is the net bounds without any whitespace: Rectangle br = Rectangle.Round(GP.GetBounds()); g.DrawRectangle(Pens.Red,br); // just for testing // now we center: g.TranslateTransform( (bmp.Width - br.Width ) / 2 - br.X, (bmp.Height - br.Height )/ 2 - br.Y); // and fill g.FillPath(Brushes.Black, GP); g.ResetTransform(); } // whatever you want to do.. pictureBox1.Image = bmp; bmp.Save("D:\\__test.png", ImageFormat.Png); } 

A small test routine to let us see the centering better:

void testPattern(Graphics g, Size sz) { List<Brush> brushes = new List<Brush>() { Brushes.SlateBlue, Brushes.Yellow, Brushes.DarkGoldenrod, Brushes.Lavender }; int bw2 = sz.Width / 2; int bh2 = sz.Height / 2; for (int i = bw2; i > 0; i--) g.FillRectangle(brushes[i%4],bw2 - i, bh2 - i, i + i, i + i ); } 

The GetBounds method returns a RectangleF; in my example it is {X=0.09375, Y=6.0625, Width=21, Height=22.90625}. Do note that due to rounding things can always be off by one..

You may or may not want to change the Graphics setting to special Smoothingmodes etc..

Also it should be noted that this will do automatic ie mechanical centering by the bounds rectangle. This may be quite different from 'optical or visual centering', which is rather hard to code and to some extent a matter of personal taste. But typography is as much an art as a profession..

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.