I am writing a program that is going to dump an SVG file, in C#. I was wondering if there is any way of measuring how big a piece of text is going to be from the C# program.
I can assume that I know the font and fontsize. But the "average size of letter"*number_of_letters is very inaccurate.
I am looking for some option like this:
1) Just figure out, from font size and font, how big the text is.
2) I could dump the SVG once, and get the measure from there (by rendering it somehow? and then reading that information from it, somehow?)
Thanks!
Figured it out:
Font stringFont = new Font("Verdana", 8, GraphicsUnit.Pixel);
Image newImage = new Bitmap(10, 10);
Graphics g = Graphics.FromImage(newImage);
SizeF stringSize = new SizeF();
g.PageUnit = GraphicsUnit.Pixel;
stringSize = g.MeasureString("Hello, this is \n a string and stuff", stringFont);
Related
This question already has answers here:
Drawing aligned strings by formatting double values
(3 answers)
How to draw a table using System.Drawing
(1 answer)
Graphics.DrawString() & leading padding spaces for Proportional Font
(1 answer)
How to create control that draws a table in panel
(1 answer)
Closed 1 year ago.
I want to create program that draws text on image. For that purpose I used this method:
private static Image DrawText(String text, Font font, Color textColor, Color backColor)
{
//first, create a dummy bitmap just to get a graphics object
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
//measure the string to see how big the image needs to be
SizeF textSize = drawing.MeasureString(text, font);
//free up the dummy image and old graphics object
img.Dispose();
drawing.Dispose();
//create a new image of the right size
img = new Bitmap((int)textSize.Width, (int)textSize.Height);
drawing = Graphics.FromImage(img);
//paint the background
drawing.Clear(backColor);
//create a brush for the text
Brush textBrush = new SolidBrush(textColor);
drawing.DrawString(text, font, textBrush, 0, 0);
drawing.Save();
textBrush.Dispose();
drawing.Dispose();
return img;
}
My problem is that I want to draw table in the image, so the table should look like:
I used this library for drawing table
And code looks like this method from above
var table = new ConsoleTable("one", "two", "three")
.AddRow("random text';", "random text", "random text")
.Configure(o => o.NumberAlignment = Alignment.Left)
.ToString();
DrawText(table, new Font("Verdana", 20), Color.Black, Color.White);
And i got this kind of image
Rows are really changed and it doesn't look like table above. I think method DrawText changed something but I don't know what exactly it is? So I need help. Sorry for my bad English
If you don't need Verdana (which isn't a monospaced font), you should be able to fix this by slightly altering your call to DrawText like so:
DrawText(table, new Font(FontFamily.GenericMonospace, 20), Color.Black, Color.White);
I'm not actually super familiar with working with fonts, so using FontFamily.GenericMonospace is sort of my best guess. You should be able to use others though. Wikipedia has a list of them.
I am writing info entered on a web form into a tiff file. My issue is where the comment box comes into play for the web form. The comment box is multi-line and when writing it on to the tiff file, some of the information entered into the comment box falls out of the tiff image.
The code for how I am trying to write it to the tiff file:-
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(800, 1000); //Creates Bitmap
Graphics g = Graphics.FromImage(bitmap);
g.DrawString("Comment: " + CommentBox.Text, outputFont, Brushes.Black, new PointF(0, 700)); // Writing the text from the comment box on to the Tiff file.
so what that means to me is, if I am writing a multi line comment as:-
"Hello Testing.
Hello Testing again and again and again and again and again and again and again.
Hello Testing again and again and again and again and again and again and again. Hello Testing again and again and again and again and again and again and again."
My tiff-file captures line elements only upto the 1000 width, the elements beyond that width do not automatically get generated in a new line.
Can anyone help me with this? ideas?
Try something like this - you can use the overload of DrawString that takes a containing rectangle, and the text should wrap within that:
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(800, 1000); //Creates Bitmap
using(Graphics g = Graphics.FromImage(bitmap))
{
RectangleF rect = new RectangleF(new PointF(0, 700), new SizeF(200,200)); // adjust these accordingly for your bounding rect
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Near;
g.DrawString("Comment: " + CommentBox.Text, outputFont, Brushes.Black, rect, drawFormat); // Writing the text from the comment box on to the Tiff file.
}
I'm trying to display the text property of a UltraButton to this unicode character- ▼ .
I've tried to copy this from the Character Map and also tried something like-
button1.Text = "\u2129"
The problem is both of them show the arrows in the designer mode in VS, but when I run the application, it shows an unrecognised symbol. I've gone through this link and this link, but the arrows only show up in the designer view, not while running the application. Why is this happening. Also, I've set the Font name to 'Arial Unicode MS'
I'm guessing the issue you are experiencing is unique to the UltraButton. From the looks of the image you just posted, you could probably get away with just using a standard Windows From Button. If you can, just open your ClassName.Designer.cs and find where your button text is being set. Copy the actual character into the text string:
this.YourButton.Text = "▼";
This shows up correctly in both the designer and when running the application.
If you really don't want to use a standard Windows Forms Button, you could always go about converting your text to an image and adding the image to the button. Would look something like this:
string text = "▼";
Font font = new Font("Arial Unicode MS", 12f);
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
SizeF textsize = drawing.MeasureString(text, font);
img.Dispose();
drawing.Dispose();
img = new Bitmap((int) textsize.Width, (int)textsize.Height);
drawing = Graphics.FromImage(img);
drawing.Clear(YourButton.BackColor);
Brush textBrush = new SolidBrush(Color.Black);
drawing.DrawString(text, font, textBrush, 0, 0);
drawing.Save();
textBrush.Dispose();
drawing.Dispose();
YourButton.Text = "";
YourButton.Image = img;
The string length can change, height is the same. The font is large for visibility.
But how do I do this?
I know painting on the control directly. But how do I do this without creating an image file, but all in memory. Because the string image will change with user interaction.
Something like ...
Image i = new Bitmap(200, 50);
Graphics g = Graphics.FromImage(i);
g.DrawString("Message", new Font("Arial", 8), Brushes.Black, new PointF(0,0));
pictureBox.Image = i;
g.Dispose();
If I use TextRenderer.DrawText() using the Graphics object provided in the OnPaintBackground my text looks perfect. If I create my own Bitmap and use the Graphics object obtained from my Bitmap my text looks terrible. It looks like it is anti-aliasing the text using black, not the bitmap's background color. I can avoid this problem if I use Graphics.DrawString(), but this method has horrible kerning problems. What should I do? How can I get TextRenderer.DrawText() to anti-alias properly using the Bitmap's contents?
Looks terrible:
Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(g, #"C:\Development\Testing\blag", font, clip, Color.White,
Color.Transparent, tf);
}
Looks good, but I want to render this onto a bitmap, NOT onto the control's surface:
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(e.Graphics, #"C:\Development\Testing\blag", font, clip,
Color.White, Color.Transparent, tf);
}
What is the difference?
The answer is not to use TextRenderer. TextRenderer is a wrapper for the GDI (not GDI+) implementation of text rendering, which has lots of features, but doesn't interoperate well with in-memory DCs as you have discovered.
Use Graphics.DrawString & Graphics.MeasureString, but remember to pass it StringFormat.GenericTypographic to get accurate size and positioning.
The reason TextRenderer was introduced initially was that GDI+ didn't support all the complex scripts that GDI's Uniscribe engine did. Over time however GDI+ support for complex scripts has been expanded, and these days there aren't any good reasons left to use TextRenderer (it's not even the faster of the two anymore, in fact quite the opposite it appears).
Really, though, unless you are running into serious, measurable performance issues just use Graphics.DrawString.
I believe the problem is that the clear type text rendering doesn't work if the background is transparent. A few possible solutions.
Option 1. Fill the background of your bitmap with a color.
If you do this (as Tim Robinson did above in his code example by using g.Clear(Color.Red)) clear type will do the right thing. But your bitmap won't be completely transparent which might not be acceptable. If you use Graphics.MeasureText, you can fill just the rectangle around your text, if you like.
Option 2. Set TextRenderingHint = TextRenderingHintAntiAliasGridFit
This appears to turn off clear type. The text will be rendered at a lower quality than clear type on a background, but much better than the mess clear type on no background creates.
Option 3. Fill the text rectangle with white, draw the text and then find all the non-text pixels and put them back to transparent.
using (Bitmap bmp = new Bitmap(someWidth, someHeight))
{
using (Graphics g = Graphics.FromImage(bmp))
{
// figure out where our text will go
Point textPoint = new Point(someX, someY);
Size textSize = g.MeasureString(someText, someFont).ToSize();
Rectangle textRect = new Rectangle(textPoint, textSize);
// fill that rect with white
g.FillRectangle(Brushes.White, textRect);
// draw the text
g.DrawString(someText, someFont, Brushes.Black, textPoint);
// set any pure white pixels back to transparent
for (int x = textRect.Left; x <= textRect.Left + textRect.Width; x++)
{
for (int y = textRect.Top; y <= textRect.Top + textRect.Height; y++)
{
Color c = bmp.GetPixel(x, y);
if (c.A == 255 && c.R == 255 && c.G == 255 && c.B == 255)
{
bmp.SetPixel(x, y, Color.Transparent);
}
}
}
}
}
I know, it's a horrible hack, but it appears to work.
The answer is to use a BuffersGraphicsContext. This is the same system that .NET uses internally when you set the ControlStyles.OptimizedDoubleBuffer style on a control.
See http://msdn.microsoft.com/en-us/library/b367a457.aspx for more information about double buffering in .NET.
Another possible solution: Draw the whole thing to the screen, bitmap with text on top, and then write some code to 'screen capture' that portion of the screen. Not practical in all cases but you're right, DrawString creates weird text and DrawText onto a bitmap looks horrible.
If your bitmap is not the same size as your display area, it might just be a resizing issue, where .NET scales the bitmap to the display size and you get funny looking text.
Can you test with a bitmap created at the same size as your display area?
Can you post the smallest program that suffers from this problem? I can't reproduce it like this -- the antialiasing looks fine:
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
public class Program
{
public static void Main()
{
Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
using (Font font = new Font("Arial", 10, GraphicsUnit.Point))
using (Graphics g = Graphics.FromImage(bmp))
{
Rectangle clip = Rectangle.FromLTRB(0, 0, 100, 100);
g.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(g, #"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}
Form form = new Form();
form.BackgroundImage = bmp;
Application.Run(form);
}
}