How can get the LineHeight of a Font given the FontSize? It seems that it is different depending on the font and not necessarily connected to the FontSize. I am using BlockLineHeight for the LineStackingStrategy.
Clarification. I understand there are methods of determining the total line height. In this case, I'm looking for the height from the baseline to the top of the font (so minus the tails of the p's etc.)
In the case of the picture above. I want the ascent.
FontFamily fontFamily = new FontFamily("Arial");
Font font = new Font(fontFamily, 16, FontStyle.Regular, GraphicsUnit.Pixel);
ascent = fontFamily.GetCellAscent(FontStyle.Regular);
ascentPixel = font.Size * ascent / fontFamily.GetEmHeight(FontStyle.Regular);
from:
http://msdn.microsoft.com/en-us/library/xwf9s90b.aspx
If you are using a Graphics object to draw on and have reference to, then you can do this.
Font myFont = new Font("Verdana", 15);
SizeF fontSize = e.Graphics.MeasureString("my text", myFont);
This will then tell you the height and width of the string. You can use this for a singluar line to test the line height.
Or by this answer here: How to calculate font height in WPF?
You can easily calculate the line height using some simple calculations.
Related
When drawing a string I get the required size by calling myGraphics.MeasureString(myString, myFont);.
Experimentally I found out that this method always returns the same height for any string or single character of a certain font. So this value seems to be a feature of the font and not a feature of the string. But there is no property or method in the font class which delivers this information.
The font class has several properties / methods returning height information but none of them gives the same value as the string measurement.
Example:
using (Graphics myGraphicsTemp = CreateGraphics())
{
Font myFont = new Font("Microsoft Sans Serif", 9F);
var size = myFont.Size; // 9
var height = myFont.Height; // 14
var lineSpacing = myFont.GetHeight(); // 13.5820293
var measuredHeight = myGraphicsTemp.MeasureString("1", myFont).Height; // 15.0820284
}
I need the height given by the string measuring method at several places in my code. So I set a variable (like measuredHeight in my example) by measuring an arbitrarily chosen character. That works but I think this has a "strong smell".
Is there a better way to find the required value?
I found the following question
(Width and height of font) but it did not answer my question.
I need to draw a string in a panel perfectly centered, horizontally and vertically.
Centering horizontally is not a big deal using the MeasureString function.
Bug, the MeasureString function returns a height that takes care of every possible char (like P and p), but not the real height of the actual string.
Here is the sample code I'm using :
using (Graphics gr = Graphics.FromImage(mBackImage))
{
gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
gr.FillRectangle(new SolidBrush(BackColor), new Rectangle(0, 0, this.Width, this.Height));
var f = new Font(Font.FontFamily, this.ClientSize.Height, FontStyle.Bold, GraphicsUnit.Pixel);
var sz = gr.MeasureString(Label, f);
var pt = new PointF((this.ClientSize.Width - sz.Width) / 2, (this.ClientSize.Height - sz.Height) / 2);
gr.DrawString(Label, f, new SolidBrush(ForeColor), pt);
}
My target is to draw numbers, and the result is that numbers are drawn a little bit too high.
Even if I change the text from "10" to "P", to "p", and I see that the text stays aligned on a "base line".
I really would like to center the text, depending on the real footprint.
How can I achieve this?
Note: this question is absolutely not duplicate of "Center text for receipt printing", because I'm talking about vertical centering, not horizontal centering.
MeasureString or MeasureCharacterRanges are returning sizes taller than the real printed chars, causing vertical alignment issues.
Bitmap bmpChar = new Bitmap(16,16);
FontFamily fontFamily = new FontFamily("Arial");
Font font = new Font(
fontFamily,
16,
FontStyle.Regular,
GraphicsUnit.Pixel);
Graphics g = Graphics.FromImage(testBmp);
g.DrawString("test", font, Brushes.Red, 0, 0);
Upper code prints two characters in 16x16 area(it has "te" of "test" while I expected only a "t"). Whats could be a platform-independent(32-bit, 64bit, NT, XP, 7, 10) way to have constant width characters for all letters and numbers when drawing them as strings onto a bitmap, in winforms?
I would use a monospaced font if it's possible. Otherwise you'd just be either stretching the letters out after rasterization or having to calculate the amount of spacing to put in between each letter which would be a lot more complicated.
I've been using a monospaced font to render a table onto a graphics object, and to align the columns of text I'd been padding the text using space characters.
I've been asked to change the font to a proportional font, and no surprise, but the columns don't line up anymore.
If given a string such as
"Bill-of-Material Edits\r\n------------------------------\r\n200 510024 Door 24\" x 58\"\r\n 3 530058 Panel 58\" x 58\"\r\n";
how do I ensure that the 3 lines up properly under the one's place on the 200 value from the line above, and subsequently have the 510024 sit directly above the 530058?
Here's the code I use to draw the string:
var fnt = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular, GraphicsUnit.Point);
StringFormat strFormat = new StringFormat(StringFormat.GenericTypographic);
strFormat.Alignment = StringAlignment.Near;
string text = "Bill-of-Material Edits\r\n------------------------------\r\n200 510024 Door 24\" x 58\"\r\n 3 530058 Panel 58\" x 58\"\r\n";
g.DrawString(text, fnt, Brushes.Black, new RectangleF(10f, 10f, 38.1062851f, 12.9231777f), strFormat);
I tried replacing the spaces with other characters such as unicode control characters (0x0080) to no avail. I've also tried using string.Format() with formatters like {0,10} which didn't help either.
What do I do to get my columns to line up?
You can't make it work like this. Draw each individual string in its column, pass the Rectangle of the column. How wide you make each column is up to you.
I'm trying to figure out a good way to auto-size a Rectangle that has text drawn inside of it. I basically want the size to have a ratio of width/height and then "grow" according to that ratio to fit the text. I've looked at Graphics.MeasureString but I don't think it does what I'm looking for (maybe it does and I'm just using it wrong).
I don't want to specify a specific width of the rectangle to be drawn. Instead I want to say find the smallest width/height to fit this text given a minimum width but the found rectangle must have some specific ratio of width and height.
This doesn't have to be specific to C#, any idea for solving this problem I'm sure can be mapped to C#.
Thanks!
I believe you can use Graphics.MeasureString. This is what I have used in my GUI code to draw rectangles around text. You hand it the text and the font you want to use, it returns to you a rectangle (technically a SizeF object - width and height). Then you can adjust this rectangle by the ratio you want:
Graphics g = CreateGraphics();
String s = "Hello, World!";
SizeF sizeF = g.MeasureString(s, new Font("Arial", 8));
// Now I have a rectangle to adjust.
float myRatio = 2F;
SizeF adjustedSizeF = new SizeF(sizeF.Width * myRatio, sizeF.Height * myRatio);
RectangleF rectangle = new RectangleF(new PointF(0, 0), adjustedSizeF);
Am I understanding your question correctly?
You should use TextRenderer.MeasureText, all controls use TextRenderer to draw text in .NET 2.0 and up.
There is no unambiguous solution to your question, there are many possible ways to fit text in a Rectangle. A wide one that displays just one line is just as valid as a narrow one that displays many lines. You'll have to constrain one of the dimensions. It is a realistic requirement, this rectangle is shown inside some other control and that control has a certain ClientSize. You'll need to decide how you want to lay it out.
On the back of my comment about the System.Windows.Forms.Label, maybe you could have a look at the code driving the painting of a Label? If you use Reflector this should get you part of the way.
There seems to be some methods on there like GetPreferredSizeCore() for example that probably have what you want which I'm sure could be made generic enough given a little work.
I've found my own solution. The following code determines the best rectangle (matching the ratio) to fit the text. It uses divide and conquer to find the closest rectangle (by decrementing the width by some "step"). This algorithm uses a min-width that is always met and I'm sure this could be modified to include a max width. Thoughts?
private Size GetPreferredSize(String text, Font font, StringFormat format)
{
Graphics graphics = this.CreateGraphics();
if (format == null)
{
format = new StringFormat();
}
SizeF textSize = SizeF.Empty;
// The minimum width allowed for the rectangle.
double minWidth = 100;
// The ratio for the height compared to the width.
double heightRatio = 0.61803399; // Gloden ratio to make it look pretty :)
// The amount to in/decrement for width.
double step = 100;
// The new width to be set.
double newWidth = minWidth;
// Find the largest width that the text fits into.
while (true)
{
textSize = graphics.MeasureString(text, font, (int)Math.Round(newWidth), format);
if (textSize.Height <= newWidth * heightRatio)
{
break;
}
newWidth += step;
}
step /= 2;
// Continuously divide the step to adjust the rectangle.
while (true)
{
// Ensure step.
if (step < 1)
{
break;
}
// Ensure minimum width.
if (newWidth - step < minWidth)
{
break;
}
// Try to subract the step from the width.
while (true)
{
// Measure the text.
textSize = graphics.MeasureString(text, font, (int)Math.Round(newWidth - step), format);
// If the text height is going to be less than the new height, decrease the new width.
// Otherwise, break to the next lowest step.
if (textSize.Height < (newWidth - step) * heightRatio)
{
newWidth -= step;
}
else
{
break;
}
}
step /= 2;
}
double width = newWidth;
double height = width * heightRatio;
return new Size((int)Math.Ceiling(width), (int)Math.Ceiling(height));
}