How to make curved text in a bitmap?

I am currently dynamically creating a bitmap and using a graphic from a bitmap to draw a line on it like this:

System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(bmp); graph.DrawString(text, font, brush, new System.Drawing.Point(0, 0)); 

This returns a rectangular bitmap with a line written straight across from left to right. I would also like to draw a string in the shape of a rainbow. How can i do this?

+4
source share
3 answers

I recently had this problem (I provided text to print on CDs), so here is my solution:

 private void DrawCurvedText(Graphics graphics, string text, Point centre, float distanceFromCentreToBaseOfText, float radiansToTextCentre, Font font, Brush brush) { // Circumference for use later var circleCircumference = (float)(Math.PI * 2 * distanceFromCentreToBaseOfText); // Get the width of each character var characterWidths = GetCharacterWidths(graphics, text, font).ToArray(); // The overall height of the string var characterHeight = graphics.MeasureString(text, font).Height; var textLength = characterWidths.Sum(); // The string length above is the arc length we'll use for rendering the string. Work out the starting angle required to // centre the text across the radiansToTextCentre. float fractionOfCircumference = textLength / circleCircumference; float currentCharacterRadians = radiansToTextCentre + (float)(Math.PI * fractionOfCircumference); for (int characterIndex = 0; characterIndex < text.Length; characterIndex++) { char @char = text[characterIndex]; // Polar to cartesian float x = (float)(distanceFromCentreToBaseOfText * Math.Sin(currentCharacterRadians)); float y = -(float)(distanceFromCentreToBaseOfText * Math.Cos(currentCharacterRadians)); using (GraphicsPath characterPath = new GraphicsPath()) { characterPath.AddString(@char.ToString(), font.FontFamily, (int)font.Style, font.Size, Point.Empty, StringFormat.GenericTypographic); var pathBounds = characterPath.GetBounds(); // Transformation matrix to move the character to the correct location. // Note that all actions on the Matrix class are prepended, so we apply them in reverse. var transform = new Matrix(); // Translate to the final position transform.Translate(centre.X + x, centre.Y + y); // Rotate the character var rotationAngleDegrees = currentCharacterRadians * 180F / (float)Math.PI - 180F; transform.Rotate(rotationAngleDegrees); // Translate the character so the centre of its base is over the origin transform.Translate(-pathBounds.Width / 2F, -characterHeight); characterPath.Transform(transform); // Draw the character graphics.FillPath(brush, characterPath); } if (characterIndex != text.Length - 1) { // Move "currentCharacterRadians" on to the next character var distanceToNextChar = (characterWidths[characterIndex] + characterWidths[characterIndex + 1]) / 2F; float charFractionOfCircumference = distanceToNextChar / circleCircumference; currentCharacterRadians -= charFractionOfCircumference * (float)(2F * Math.PI); } } } private IEnumerable<float> GetCharacterWidths(Graphics graphics, string text, Font font) { // The length of a space. Necessary because a space measured using StringFormat.GenericTypographic has no width. // We can't use StringFormat.GenericDefault for the characters themselves, as it adds unwanted spacing. var spaceLength = graphics.MeasureString(" ", font, Point.Empty, StringFormat.GenericDefault).Width; return text.Select(c => c == ' ' ? spaceLength : graphics.MeasureString(c.ToString(), font, Point.Empty, StringFormat.GenericTypographic).Width); } 

screenshot of curved text in program output

+16
source

I think the only way is to make each character individually and use

 Graphics.RotateTransform 

to rotate the text. You will need to work out the angle of rotation and compensate for the offset. you can use

 Graphics.MeasureCharacterRanges 

to get the size of each character.

+1
source

Undoubtedly, in GDI + it is not possible to bind strings to a path (this is what you would be looking for).

Thus, the only way to do this is by hand. This means splitting the string into characters and placing them based on your own path calculations.

If you do not want to put a lot of work into it, you should try to find a library (potentially a complete replacement for GDI +) to do this or abandon your rainbow.

With WPF, you can render text along a path ( see link to method )

0
source

All Articles