MeasureString weird behavior - c#

If I calculate size in terms of width for text using below it give me says 500
intWidth = (int)objGraphics.MeasureString(String.concat(sImageText1, sImageText2), objFont).Width;
but if i do like this
intWidth = (int)objGraphics.MeasureString(sImageText1, objFont).Width + (int)objGraphics.MeasureString(sImageText2, objFont).Width;
I search lot and have done lots of different scenarios but still getting difference if we measure string width using "MeasureString" with full text or part by part.
Why is this?

The documentation has the answer:
The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString. To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.
The emphasized parts are what is relevant here.
To fix your code, add the necessary parameters:
intWidth = (int)objGraphics.MeasureString(sImageText1, objFont, 1024, Stringformat.GenericTypographic).Width
+ (int)objGraphics.MeasureString(sImageText2, objFont, 1024, StringFormat.GenericTypographic).Width;

Related

Image brightness for big images c#

I use this link to add my program the capability to adjust the brightness of the image. This code is ok but it takes time to adjust the brightness(Image file size 1.8mb). When I try the lower quality image it instantly adjusts the image(Image file size 100KB). Is there any efficient way to adjust the brightness of the image.
The code seems to use GetPixel and SetPixel on regular Bitmaps. This is a bad idea because it is so slow.
To manipulate a single pixel of a Bitmap it must be locked (which Get/SetPixel do behind the scenes) and doing it on a pixel by pixel basis means that for a 1000x1000 sized image a million locking/unlocking operations must be performed. This creates an enormous overhead.
Method one
One way to avoid this is to lock the whole bitmap with the LockBits function. Now we can loop over the pixels and modify them.
Two notes about this method:
What we now access are the raw bytes of each pixel, that is each channel separately: either BGR or BGRA, depending on the pixel format. This means that the channels are physically reversed from the usual RGB/ARGB format of the Color methods.
To loop over the physical bitmap pixel rows we also need to add some stride to each row, which pads the rows to a multiple of 4 bytes. Also see here
For some examples you may want to browse over some of these posts. Note especially this one which uses a delegate to allow for flexible operations!
(Note that several of the posts use 2 or even 3 locked bitmaps because they aim at combining images..)
Method two
Another way to get around the overhead of locking pixels one by one are ready-made bitmap classes that help by locking themselves as a whole. Here and here are examples I didn't try myself.
Method three
Finally there is a very elegant method for image manipulation, which is both rather simple and really fast; also professionally crafted for best results: You can set up a ColorMatrix.
It will let you change brightness, gamma, hues and then some. Here is a very nice introduction.
The only drawback is, that is limited to some fixed operations, so you can't create custom filters for other fancy stuff, like photoshop-type layer modes or others, especially those that need to process neighbouring pixels e.g. for blurring..
But if all you want is changing brightness, this is what I would recommend!

Formatting text with padding does not line up in C#

I am fairly new to programming and I just wrote a simple application in C# .NET to retrieve information about system drive space. The program functions fine but I'm struggling with formatting the output.
See output:
I'm trying to use padding to get the text to line up in sort of a column format within a rich text box but the output doesn't line up because if there are multiple drives, the drive names are different lengths which throws off the padding. Even if the drive letter comes back one as M: and the other as I: the difference in the size of the letter is enough to throw off the alignment while padding.
I am wondering if there is a way to force each string value to a specific length so the padding is applied evenly or if maybe there's an even better way to format my output. Thank you in advance for your time and let me know if any further information would be helpful!
Note: One of the comments asked an important question, regarding whether the question refers to the System.Windows.Forms.RichTextBox (WinForms) or the System.Windows.Controls.RichTextBox (WPF) control. This answer applies only to the WinForms version of RichTextBox, so if you're using WPF, this doesn't apply.
The most important thing, and this was mentioned in the comments, is that you'll need to use a Monospaced font.
Since you stated you're using a RichTextBox, you'll need to know how to set it to use whatever monospaced font you've chosen.
To do that, you can use the RichTextBox.SelectionFont property.
For more general instructions, refer to this MSDN article: Setting Font Attributes for the Windows Forms RichTextBox Control
Once you set the RichTextBox.SelectionFont property, only text added to the control afterwards will use the specified font. To apply the font to existing text (i.e. you populate the RichTextBox and then change the font to an appropriate monospaced font), take a look at this answer, which tells you precisely what to do.
Once that's done, there remains the simple matter of adding the appropriate amount of whitespace to the end of each string, such that the next piece of data appears at the appropriate position. You'll probably be using String.PadRight, but for more general information about padding strings, check out this MSDN article: Padding Strings in the .NET Framework
Here is string formatting example:
string varOne = "Line One";
double varTwo = 15/100;
string output= String.Format("{0,-10} {1,5:P1}", varOne, varTwo);
//expected output is
//Line One 15 %
where formatting properties in curly brackets are:
{index[,alignment][ :formatString] }

Measure String in MigraDoc TextFrame

I've already tried asking the question on their forums but as yet to have received a response, hope someone can help me on here.
I have setup a custom report screen in asp.net where people can drag labels and fields and Migradoc produces this accordingly by using textframes and top/left/width/height properties to lay them out in the same place they were dragged/resized to. This all works great however one issue I have is if the text is longer than the textframe it runs off the page and I need the page to move on accordingly whilst retaining the other objects in place.
I can use the below code to measure a string:
Style style = document.Styles["Normal"];
TextMeasurement tm = new TextMeasurement(style.Font.Clone());
float fh = tm.MeasureString(value, UnitType.Millimeter).Height;
float fw = tm.MeasureString(value, UnitType.Millimeter).Width;
But it's only useful for comparing the width against the frame and not the height because it could be different once put into a smaller area. Does anyone know how I can measure this string based on bound width/height values i.e. within a text frame.
Look at the CreateBlocks() method in the XTextFormatter class and how it calls MeasureString in a loop to break the text to multiple lines.
I'm afraid you have to implement such a loop yourself.
Or maybe use the PrepareDocument() method of the DocumentRenderer class to let MigraDoc do the work and just query the dimensions when it's done.
BTW: a similar question had been asked at the forum before:
http://forum.pdfsharp.net/viewtopic.php?p=3590#p3590
Answer includes some source code.
An easy way to do this (using I-liked-the-old-stack-overflow's link) is to add the PdfWordWrapper class to your project and then calculate the dimensions of your text as follows:
var wrapper = new PdfWordWrapper(g, contentWidth); //g is your XGraphics object
wrapper.Add("My text here", someFont, XBrushes.Black);
wrapper.Process();
var dimensions = wrapper.Size; //you can access .Height or .Width
//If you want to reuse the wrapper just call .Clear() and then .Add() again with some new text

how to measure width of a string precisely?

First of all, question How to measure width of character precisely? which is answered, doesn't really help for this case, so this isn't a duplicate of that.
I have a string. I draw using graphics.DrawString, however when I need to put another one after it, I need to know the precise width of previous string.
For this I use graphics.MeasureString with:
StringFormat format = new StringFormat(StringFormat.GenericTypographic);
format.Alignment = StringAlignment.Center;
format.Trimming = StringTrimming.None;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
I have tried many other functions, just as TextRendered.MeasureText however all of them fail, with all possible combinations of parameters.
the mentioned combination of MeasureString is most close to what I need (it works in most cases, except for special characters), however using characters like # break it. The width is either shorter or longer.
Is there a way to get a precise size of text produced by DrawString function? How does the DrawString calculate the size of drawing area? It must be clearly some other function because the size always differ.
The source code of whole application is here https://gitorious.org/pidgeon/pidgeon-main/ (File where I work with this, is https://gitorious.org/pidgeon/pidgeon-main/blobs/master/scrollback/SBABox.cs)
You just need to eliminate extra width. You can do this by using string format:
GdipStringFormatGetGenericTypographic()
You could also use:
float doubleWidth = g.MeasureString(text+text,...).Width;
float singleWidth = g.MeasureString(text).Width;
float textWidth = doubleWidth-singleWidth;
This will allow you to work with other languages such as Japanese.
On codeproject, Pierre Anaud's solution was to use MeasureCharacterRanges, which returns a region matching exactly the bounding box of the specified string:
static public int MeasureDisplayStringWidth(Graphics graphics, string text, Font font)
{
System.Drawing.StringFormat format = new System.Drawing.StringFormat ();
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, 1000, 1000);
var ranges = new System.Drawing.CharacterRange(0, text.Length);
System.Drawing.Region[] regions = new System.Drawing.Region[1];
format.SetMeasurableCharacterRanges (ranges);
regions = graphics.MeasureCharacterRanges (text, font, rect, format);
rect = regions[0].GetBounds (graphics);
return (int)(rect.Right + 1.0f);
}
I'm a little late to the party here, but I was trying to do something similar and stumbled on this question. You've probably already seen the following remark from the documentation for the Graphics.MeasureString method on MSDN:
The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString. To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.
It seems that you were trying to follow this advice because you're using StringFormat.GenericTypographic as a starting point for your custom StringFormat object. However, the line
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
effectively negates the fact that you started with StringFormat.GenericTypographic because it clears any previously set flags. What you probably meant to do is set the StringFormatFlags.MeasureTrailingSpaces flag while preserving the other flags, like so:
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
Try to use this methods:
GDI+ (graphics.MeasureString and graphics.DrawString) >> System.Drawing.Graphics
GDI (TextRenderer.MeasureText and TextRenderer.DrawText)
It also may help you:
Write a custom measure method:
Split entry string on special characters
Use above .net methods
Calculate width of special characters and sum ...
Read Ian Boyd answer
A method using Graphics.MeasureCharacterRanges to return all the rectangles enclosing each individual letter in a string and their positions is given here: Measure character positions when drawing long strings in C#
I have used the MeasureCharactersInWord and MeasureCharacters methods from that post, then in order to find the exact width without the spaces added to each side of the string, I use this code:
var w = 0F;
var rects = MeasureCharacters(Graphics.FromHwnd(IntPtr.Zero), font, text);
if (rects.Count>0)
{
if (rects.Count == 1)
{
w = rects.First().Width;
}
else
{
var r0 = rects.First();
var rN = rects.Last();
w = rN.X - r0.X + rN.Width;
}
}
Note that the height of the rectangle is the height of the font and not of the character itself. If you need the height check this post: Determining exact glyph height in specified font
A final note: the reason why I used MeasureCharacterRanges is because all the other methods I tried were failing at giving me a bounding box without space to the left and right of the text. This post The wonders of text rendering and GDI gives a method to get the string width and remove this space using TextRenderer so the whole thing can be done in about two lines of code. I haven't checked the result though.

Find char width in pixels for various Arial fontsizes

I have a program that is manually generating a PDF using PDFsharp in C#. Although it is rather tedious I have to use it and am nearing completion of the task. Only one issue remains.
Problem: I am wondering how I can find out what the width of a given char is for a given font size in Arial.
I am having trouble coming up with a more precise text wrapping method. Right now one defines a width of box in pixels and then proceeds to write out a string in that box. I kinda just guess at the max length of the string that can fit in the box and there are some visual oddities that crop up from time to time.
Any help?
Thanks
I'm not sure from your question whether you want a way to measure the size of a string specifically using PDF#, or just a generic way.
In general .Net, you can use the MeasureText method of the TextRenderer class (from Windows forms):
TextRenderer.MeasureText("some text", new Font("Arial", 1.0f, FontStyle.Regular))
This will return a Size instance that will contain Width=12, Height=2.
In the days of True Type fonts with kerning etc. there is not a single character width.
The width of the string "VA" is probably less then the sum of the widths of the strings "V" and "A".
Summing up the widths if individual characters is a starting point - but finally you have to measure the complete string.
PDFsharp includes the class XTextFormatter (with full source code) that does this line wrapping. It can be adapted for specific requirements.
It uses gfx.MeasureString(token, this.font).Width to measure the width of a string.
XGraphics.MeasureString(string s, Font f) does the trick.
//l_Page is of type PdfPage
var l_Graphics = XGraphics.FromPdfPage( l_Page );
var l_TitleFont = new Font( "Arial", 15f, GraphicsUnit.World )
var l_Title = "Hallo Welt";
//l_TitleSize will be of type XSize and has properties for Width and Height
var l_TitleSize = l_Graphics.MeasureString( l_Title, l_TitleFont );

Categories

Resources