Calculate text width based on available height? - c#

Is there any way to calculate text width based on available height in c# on windows forms?
Edit: I have the font size. I want to calculate the minimum width required for drawing the text considering the line could be wrapped.

what you can do is to measure a string in a default size with this method:
(g is a Graphics Object)
g.MeasureString("area", Font, maxWidth)
you scale the fontsize depending on the proportion measuredHeight to availableHeight. After you can remeasure the string with the height of the available area
or you just measure it to get the proportions and calculated the expected width like that:
float measureFontSize = 5;
SizeF measuredBox = g.MeasureString("my string", new Font("Arial", measureFontSize));
double measuredProportion = measuredBox.Width / measuredBox.Height;
double expectedWidth = measuredProportion * wishedHeight;

Related

Calculate coordinates rectangle for picture cropping, when picture bigger than rectangle

I'm developing my own picture viewer and in the process of creating an image cropping method. It does work with my current code. However, the application is dynamically resizing the image to fit the user's screen. So when it is resized, the calculated X.Y coordinates of the image are incorrect. I'm not very good at math, so I don't know how to calculate that.
This is the code that I am using
internal static Int32Rect GetCrop()
{
var cropArea = cropppingTool.CropTool.CropService.GetCroppedArea();
var x = Convert.ToInt32(cropArea.CroppedRectAbsolute.X);
var y = Convert.ToInt32(cropArea.CroppedRectAbsolute.Y);
var width = Convert.ToInt32(cropArea.CroppedRectAbsolute.Width);
var height = Convert.ToInt32(cropArea.CroppedRectAbsolute.Height);
return new Int32Rect(x, y, width, height);
}
The cropArea variable is from my own modified version of https://github.com/dmitryshelamov/UI-Cropping-Image. It is a Rect that returns X and Y coordinates and width and height from the user drawn square, used to select cropping area of image.
I have the variables for resized image width and height, and the original pixel width and pixel height of the images. The cropping UI uses the resized variables, to fit on the user's screen.
For clarity, the image size is calculated as so, with image control set to Stretch.Fill
double width = sourceBitmap.PixelWidth;
double height = sourceBitmap.PixelHeight;
double maxWidth = Math.Min(SystemParameters.PrimaryScreenWidth - 300, width);
double maxHeight = Math.Min(SystemParameters.PrimaryScreenHeight - 300, height);
var aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
width *= aspectRatio;
height *= aspectRatio;
image.Width = width;
image.Height = height;
So the question is, how do I calculate the offset between rendered size and actual pixel size?
If I understand this: you've calculated a ratio named aspectRatio to scale the image from it's actual size to the size of the screen. You have a cropping tool that gives you coordinates based on the scaled size image, and you want to convert those coordinates so they can be applied to the image's original size.
Assuming the above is right, this should be simple.
If the scaled height and width are calculated by:
scaledWidth = originalWidth * ratio
scaledHeigth = originalHeigth * ratio
Then you can reverse the multiplication by dividing instead:
originalWidth = scaledWidth / ratio
originalHeight = scaledHeight / ratio
This also applies to any coordinates within the image. You can take coordinates from the scaled image, and convert them into coordinates for the original image like so:
originalX = scaledRect.X / ratio
originalY = scaledRect.Y / ratio
originalWidth = scaledRect.Width / ratio
originalHeight = scaledRect.Height / ratio
You'll have to be careful to make sure that none of the values of scaledRect are 0, since division and 0 don't mix. A value of 0 in the scaled coordinate will also translate to 0 in the original coordinate space, so 0 should just stay 0. You can do this with if statements.

how to check whether a string can fit into richtextbox visible area

I want to divide a very large string into slices so that each slice can fit into the visible area of a richtextbox so that the horizontal scroll bar will not show.
I would like to know how to determine whether a string can fit into the richtextbox's visible area without changing the richtextbox's value.
I searched for the solution and most results I found suggest that MeasureText / MeasureString should be used, but it seems these two function assume there is only one line(not wrapped).
Is there any way to find out the height of a multiple line string which will be set into a richtextbox?
MeasureText and MeasureString functions has overloads that accept textarea width, height and TextFormatFlags(TextBoxControl, WordBreak e.t.c)
You can compare your text size with RichTextBoxControl size
Size stringSize = new Size();
string text = SomeText();
stringSize = TextRenderer.MeasureText(text, richTextBox1.Font, new Size(richTextBox1.Size.Width, richTextBox1.Size.Height), TextFormatFlags.WordBreak);
string r = string.Format("RTB Width : {0}\r\n", richTextBox1.Size.Width);
r += string.Format("RTB Height : {0}\r\n", richTextBox1.Size.Height);
r += string.Format("TEXT Width : {0}\r\n", stringSize.Width);
r += string.Format("TEXT Height : {0}", stringSize.Height);
MessageBox.Show(r);

MS Chart Rectangular Annotation width in percent and not pixel

why is it that the MS chart rectangular annotation width is in percent and not pixel like msdn says it is? https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.annotation.width(v=vs.110).aspx
This is what msdn says
Gets or sets the width, in pixels, of an annotation.
I'd like to set my width to be pixels like it states. Am I missing something here?
Congratulations, you have found a bug in the documentation! Easy to spot simply by following the link to the Annotation.Height docs..
The dimensions of an Annotation, as many others in a Chart control, are indeed given in percentages. This has the advantage that they quite cleverly grow and shrink with the Chart control just like many other elements.
So if you double the width of the chart you basically double the space for the shown DataPoints and if your Annotation went over a 1/3 of the width before it will still do that after you have resized the chart..
Which is nice.
But not what you wanted..
So to set the size to a fixed size in pixels you need to do this:
Calculate the size you want in percentages and set it
Repeat whenever you resize the chart or its layout
The real problem is the calculation: If you look at the Chart.ClientSize you get the size in pixels and to get n pixels you need to do something like this:
float WidthInPercent = 100f * n / Chart.ClientSize.width;
This however does not take into account the various elements your Chart probably has : The Size of an Annotation is not really calculated as direct percentages of the Chart's size.
Instead it is calulated as percentages of the InnerPlotPosition of the ChartArea CA.
InnerPlotPosition by default is set to Auto so accessing its values, e.g. CA.InnerPlotPosition.Width will return 0f; but you can get at the (current!!) values by doing this:
RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
The same goes for the Size/Position of the ChartArea itself:
RectangleF CAP = CA.Position.ToRectangleF();
Now you can combine these percentages with the (current!) Chart.ClientSize to find out which percentage you need to achieve a certain pixel size..
Note that these values will change when resizing because the outer extras, like Legend and Axis and Labels etc. will not resize, so their relative sizes will grow or shink in relation to their containing elements..
So you need to recalculate upon each Resize event, or, better: write a function to do it for you which you can call wheneber needed..
The result is an Annotation that will (pretty much, due to rounding) maintain its size, no matter how you resize the Chart..
Here are some helpful functions:
This one returns the current ClientRectangle of a ChartArea in pixels
RectangleF ChartAreaClientRectangle(Chart chart, ChartArea CA)
{
RectangleF CAR = CA.Position.ToRectangleF();
float pw = chart.ClientSize.Width / 100f;
float ph = chart.ClientSize.Height / 100f;
return new RectangleF(pw * CAR.X, ph * CAR.Y, pw * CAR.Width, ph * CAR.Height);
}
This one is similar and returns the current ClientRectangle of a ChartArea's InnerplotPosition in pixels:
RectangleF InnerPlotPositionClientRectangle(Chart chart, ChartArea CA)
{
RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
RectangleF CArp = ChartAreaClientRectangle(chart, CA);
float pw = CArp.Width / 100f;
float ph = CArp.Height / 100f;
return new RectangleF(CArp.X + pw * IPP.X, CArp.Y + ph * IPP.Y,
pw * IPP.Width, ph * IPP.Height);
}
Finally one that converts a size in pixels to one in percentages, again valid only currently, i.e. until the next changes in size or layout..:
SizeF Pixels2Percent( ChartArea CA, int w, int h)
{
RectangleF IPPR = InnerPlotPositionClientRectangle(chart1, CA);
float pw = 100f * w / IPPR.Width ;
float ph = 100f * h / IPPR.Height ;
return new SizeF(pw, ph);
}
Lets have a look at the result before and after some resizing:
As you can see the size stay the same.
Also note the colored rectangles I draw in the Paint event to demostrate the new functions!
Here is the Paint event:
private void chart1_Paint(object sender, PaintEventArgs e)
{
ChartArea CA = chart1.ChartAreas[0];
e.Graphics.DrawRectangle(Pens.Violet,
Rectangle.Round(ChartAreaClientRectangle(chart1, CA)));
e.Graphics.DrawRectangle(Pens.LimeGreen,
Rectangle.Round(InnerPlotPositionClientRectangle(chart1, CA)));
}
Here is the Resize event:
private void chart1_Resize(object sender, EventArgs e)
{
sizeAnn(ra, new Size(24, 36));
}
And here the sizing function:
void sizeAnn(RectangleAnnotation ra, Size sz)
{
ChartArea CA = chart1.ChartAreas[0];
SizeF pixelPercent = Pixels2Percent(CA, sz.Width, sz.Height);
ra.Width = pixelPercent.Width;
ra.Height = pixelPercent.Height;
}
Yes, we cannot set it in % or px as the property value is set to double.
Secondly, pixle = H multiplied by W. but you are only setting the width of chart then how can you set it in pixle? It fundamentally not possible. I hope you will understand what I mean.
I know the OP wanted to set the width in pixels, but in case some people (like me) want to set the width neither in pixels nor in %, but according to the actual values, just set :
annotation.IsSizeAlwaysRelative = False
annotation.Width = whatEverValue

How do I get the position of the text baseline in a Label and a NumericUpDown?

I'm trying to align a Label and a NumericUpDown by their text baselines. I'm doing it in code, rather than the designer. How do I get the position of the text baseline?
// to render text with baseline at coordinates (pt.X, pt.Y) :
Font myFont = Label1.Font;
FontFamily ff = myFont.FontFamily;
float lineSpace = ff.GetLineSpacing(myFont.Style);
float ascent = ff.GetCellAscent(myFont.Style);
float baseline = myFont.GetHeight(ev.Graphics) * ascent / lineSpace;
PointF renderPt = new PointF(pt.X, pt.Y - baseline));
ev.Graphics.DrawString("Render this string", myFont, textBrush, renderPt);
For the Label control, you can get the position of the bottom of the text this way:
Assuming the .TextAlign is set to TopLeft or TopCenter or TopRight, the bottom of the text in the Label control can be found by this method:
dim btmOfText as single
btmOfText = Label1.Font.GetHeight + Label1.Top
The .GetHeight method returns the height, in pixels of the current font used by the Label.
If the .TextAlign is Middle or Bottom, then you need to do a slightly more complex calculation.
This same method will also work with the NumericUpDown control.

Transform pixel height of image to printing size used by graphics object

As part of a print procedure of my application I'm trying to print a list of images scaled down to a specified width and placed one below the other. The problem is I can not figure out how to transform the height in pixels of the images to the height in the units used by the graphics object during printing. How do I calculate the imageHeightPrint variable correctly?
This code snippet is the part of the image printing loop that scales down the image and calculates it's height and the placement of the next image.
Image image = Image.FromStream(imageStream);
// Get proportional correct height
int imageHeight = image.Height * imageWidth / image.Width;
Image imageToPrint = image.GetThumbnailImage(imageWidth, imageHeight, null, IntPtr.Zero);
float imageHeightPrint = e.Graphics.DpiY * imageToPrint.Height / imageToPrint.VerticalResolution;
e.Graphics.DrawImage(imageToPrint, e.MarginBounds.Left, yPos);
yPos += imageHeightPrint;
I found the correct solution my self after dissecting the documentation.
This line:
float imageHeightPrint = e.Graphics.DpiY * imageToPrint.Height / imageToPrint.VerticalResolution;
Should be changed into this:
float imageHeightPrint = imageToPrint.Height /
imageToPrint.VerticalResolution * 100;
The biggest thing I missed was that the height-in-print should be in hundredths of an inch.

Categories

Resources