I wanted to know how to word-wrap in C# when I came across a very good solution to my problem on word-wrapping text in a line in this URL. Unfortunately, I do not have enough reputations to ask the OP directly about one specific problem I am having(and most likely people dealing with this will be having indefinitely)
Problem Description:
I can word-wrap a string if it needs to be word-wrapped with this code:
Graphics PAddress = e.Graphics;
SizeF PAddressLength = PAddress.MeasureString("Residential Address: " + RAddressTextBox.Text, new Font(fontface, fontsize, FontStyle.Regular),700);
PAddress.DrawString("Residential Address: "+PAddressLength + RAddressTextBox.Text, new Font(fontface, fontsize, FontStyle.Regular), Brushes.Black, new RectangleF(new Point(pagemarginX, newline()),PAddressLength),StringFormat.GenericTypographic);
However, I could not find the place to receive a trigger whenever the word-length overflows from a single line.
for example:
In LINE-2 of that code, whenever the wordlength exceeds 700px, it moves to the next line. It does that by following the RectangleF to wordwrap. It is doing so automatically, which is a problem since that makes it difficult to know whether it has crossed 700px or not.This is the format in which information is displayed whenever I tried to print PAddressLength:
{Width=633.1881, Height=47.14897}
I am thinking that If I can extract the value of width from that using PAddressLength.Width ,then I can partially solve this problem. But with that, I will need to calculate if the remaining space(i.e 700px - 633.1881px ) will accommodate the next word or not(if there is one)
BREAKING DOWN THE PROBLEM:
I already know how to word-wrap when there is a string longer than what specify by using Graphics.MeasureString as given in this solution in another question.
But that^ process happens automatically, so I want to know how to detect if the word-wrap has occured(and how may lines it has wrapped with each line being 700px width maximum)
I need to know the number of lines that have been wrapped in order to know the number of times to execute newline() function that I wrote, which gives appropriate line spacing upon executing each time.
ADDITIONALLY, (bonus question; may or maynot solve) Is there some way to extract the value 633.1881 and then calculate whether the next word fits in ( 700 - 633.1881 )px space or not?
There is an overload to MeasureString that returns the number of lines used in an out parameter: https://msdn.microsoft.com/en-us/library/957webty%28v=vs.110%29.aspx
Related
Using iTextSharp, how can I determine if a parsed chunk of text is both bolded and underlined?
Details:
I'm trying to parse .PDF files in C# specifically for text that is both bolded and underlined. Using ITextSharp, I can derive from LocationTextExtractionStrategy and get the text, the location, the font, etc. from the iTextSharp.text.pdf.parser.TextRenderInfo object passed to the overridden .RenderText method.
However, determining if the text is Bold and/Underlined from the TextRenderInfo object has not been straight forward.
I tried to use TextRenderInfo.GetFont() to find the font properties, but was unsuccessful
I can currently determine if the text is Bold or not, by accessing the private Graphics State field on the TextRenderInfo object and checking it's .Font.PostscriptFontName property for the word "Bold" (Ugly, but appears to work.)
Biggest issue: I haven't found anything to determine if the text is underlined. How can I determine this?
Here is my current attempt:
private FieldInfo _gsField = typeof(TextRenderInfo).GetField("gs",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
//Automatically called for each chunk of text in the PDF
public override void RenderText(TextRenderInfo renderInfo)
{
base.RenderText(renderInfo);
//UNDONE:Need to determine if text is underlined. How?
//NOTE: renderInfo.GetFont().FontWeight does not contain any actual information
var gs = (GraphicsState)_gsField.GetValue(renderInfo);
var textChunkInfo = new TextChunkInfo(renderInfo);
_allLocations.Add(textChunkInfo);
if (gs.Font.PostscriptFontName.Contains("Bold"))
//Add this to our found collection
FoundItems.Add(new TextChunkInfo(renderInfo));
if (!_lineHeights.Contains(textChunkInfo.LineHeight))
_lineHeights.Add(textChunkInfo.LineHeight);
}
Full source code of current attempt at: GitHub Repository (Two examples (example.pdf and example2.pdf) are included with text similar to what I'll be searching through.)
I tried to use TextRenderInfo.GetFont() to find the font properties, but was unsuccessful
I can currently determine if the text is Bold or not, by accessing the private Graphics State field on the TextRenderInfo object and checking it's .Font.PostscriptFontName property for the word "Bold" (Ugly, but appears to work.)
I don't quite understand this differentiation. TextRenderInfo.GetFont() is exactly the same as the Font property of the private Graphics State field of TextRenderInfo.
That being said, though, this is indeed one of the major ways to determine boldness.
Bold writing in PDFs is achieved either using
explicitly bold fonts (which is the better way); in this case one can try to determine whether or not the fonts are bold by
looking at the font name: it may contain a substring "bold" or something similar;
looking at some optional properties of the font, e.g. font weight, but beware, they are optional...
inspecting the embedded font file if applicable.
Neither of these methods is fool-proof;
the same font as for non-bold text but using special techniques to make them appear bold (aka poor man's bold), e.g.
not only filling the glyph contours but also drawing a thicker line along it for a bold impression,
drawing the glyph twice, the second time slightly displaced, also for a bold impression.
Underlined writing in PDFs is usually achieved by explicitly drawing a line or a very thin rectangle under the text. You can try and detect such lines by implementing IExtRenderListener, parsing the page in question with it to determine line locations, and then match with text positions during text extraction. Both can also be done in a single pass but beware, the underlines need not be drawn before the text or even shortly thereafter, the pdf producer may first draw all text and only then draw all underlines. Furthermore, I've also come across a funny construction, very short (e.g. 1pt) very wide (e.g. 50pt) vertical lines effectively are seen as horizontal ones...
IExtRenderListener extends the IRenderListener with three new methods, ModifyPath, RenderPath, and ClipPath. Whenever some path is drawn, be it a single line, a rectangle, or some very complex path, you'll first get a number of ModifyPath calls (at least one)
/**
* Called when the current path is being modified. E.g. new segment is being added,
* new subpath is being started etc.
*
* #param renderInfo Contains information about the path segment being added to the current path.
*/
void ModifyPath(PathConstructionRenderInfo renderInfo);
defining the lines and curves the path consists of, then at most one ClipPath call
/**
* Called when the current path should be set as a new clipping path.
*
* #param rule Either {#link PathPaintingRenderInfo#EVEN_ODD_RULE} or {#link PathPaintingRenderInfo#NONZERO_WINDING_RULE}
*/
void ClipPath(int rule);
(if and only if the path shall serve as clip path for the following drawing operations), and finally exactly one RenderPath call
/**
* Called when the current path should be rendered.
*
* #param renderInfo Contains information about the current path which should be rendered.
* #return The path which can be used as a new clipping path.
*/
Path RenderPath(PathPaintingRenderInfo renderInfo);
defining how that path shall be drawn (any combination of filling its interior and stroking the path itself).
I.e. for recognizing underlines, you'll have to collect the path pieces provided via ModifyPath and decide whether they might describe one or more underlines as soon as the RenderPath call comes.
Theoretically underlines could also be created differently, e.g. using a bitmap image, but I'm not aware of pdf producers doing so.
By the way, in your example PDF underlines appear consistently to be drawn using a MoveTo to the line starting point, a LineTo to its end, and then a Stroke to simply stroke the path. Thus, you'll get two ModifyPath calls (one with operation value MOVETO, one with LINETO) and one RenderPath call (with operation STROKE) respectively for each underline.
In DOCOTIC.pdf library there is a method responding as true or false.
In C#
bool FONT_ITALIC = data.Font.Italic;
bool FONT_UNDERLINE = data.Font.Underline;
Check for the value of FONT_ITALIC/FONT_UNDERLINE.
I have tried to use the same, but couldn't get correct value always.
Any suggestions are welcome.
Are there solutions for the following problem?
A user enters an X coordinate, Y coordinate, length, and (optional)
number. If a number was entered, print a straight line with the
specified length, followed by the (x,y) coordinates. If n=2, print
bisecting lines with the specified length. If n=3, print a triangle
where the lines are the specified length.
Assuming you want ASCII drawings, here's how this would work. Note that I'm just providing an outline of how this would work, since I don't want to answer the interview question for you. Also, this is not production-quality since there's no validation (or differentiation between lack of input and invalid input).
First, let's ask the user for their input. Console.ReadLine is how you do this. Since we'll be getting input four times, let's make it a method. The return type can be int since everything we're getting from the user is a number. We'll print the prompt (passed in as an argument) with Console.WriteLine and then return the result of Console.ReadLine after converting it to an int (do you need validation)? Since n is optional, maybe return something like -1 if the user doesn't enter anything.
Store the results so that we can use them later in our calculations. Use an if... else if (or switch) statement to determine if n was supplied by the user and take action accordingly. We can call different methods depending on whether we want to draw a line, two bisecting lines, or a triangle.
Is the actual drawing the problem? I'm having trouble understand exactly where you need help, and the drawing of the shapes would be more complicated. For now, though, this should get you on the right track.
I am developing a Windows forms application that includes a DataGridView. This DataGridView has 3 columns, all of which are simply text cells:
Timestamp
Connection
Message
The issue I'm running into is that when I add a row (programmatically), I'm finding that the text disappears if it is too long. To be specific, if the text exceeds 4563 characters in length, then the text disappears.
I know that the DataGridViewTextBoxColumn class has a property call MaxInputLength that can limit the number of characters entered. But according the the Documentation, it only affects text that is input manually by the user. I, however, am inputting this text programmatically.
Just to make sure though, I set this property very high but the disappearing text issue still arises when I pass the 4563 character limit.
One thing I have noticed is that the text is still there (i.e. the scroll bar along the bottom can still be scrolled as though the text is still there) but I cannot see the text itself. I can also edit the text.
I can add characters until the 4563 limit but as soon as I pass that, the text disappears. If I press backspace to return to exactly 4563 characters, the text reappears.
I am developing this using .NET 4.0, since I have to support Windows XP.
Here's the short answer that will probably disappoint you: It's a reported bug and verified by Microsoft, closed as "Not important enough to fix". There may be more instances of it, but it's been known since at least 2011 DataGridView control shows blank cell if large string is entered and column resized to max. The "workaround" is to just limit the size of the cells width, but for you that may not be satisfactory.
However, curiosity got the best of me so I started looking into it a little deeper; Here's the first observation worth mentioning:
If you look at the series of pictures, you'll notice I replicated your problem with the default font size/style and the specific number 5460. What's so special about 5460? Well, nothing in particular, except that as your character threshold crosses it the ContentBounds and Width of the column passes 32767. What's so special about 32767? Other than being the default MaxInputLength of a DataGridViewTextBoxCell, it's the upper limit of a signed short or Int16 (2^15-1). I highly doubt it's a coincidence the issue is occurring here, though not cause of anything to do with MaxInputLength per se. I'd be willing to bet you first noticed the issue at 4563 characters because your font size expanded the width to 32767 as well.
The next question, is why? I'm not really sure. I started following the rabbit hole and disassembled some of the .NET 4.0 DataGridView* libraries to find out. It's a pretty massive and complicated control, and I haven't been able to draw any definite conclusions, but one thing I found that's worth noting is the absolute maximum width a column can assume is 65536, the value of an UNsigned Int16 (2^16):
You see this check in a lot of private internal places when adding or resizing a column, and I tested it. The size won't go larger
This is ironic for two reasons. For one, using the default settings, you can only display 10922 characters (65536 / 6 pixels per character) in a column despite the editing input length being 32767 characters, and programmatically arbitrary.
Second, why would this issue start cropping up at exactly the max of the signed variant of the columns max width? Hmmmm. This is totally a guess, but I think somewhere along the line the max value for whatever renders the text was set as a regular short instead of an unsigned short... or something along those lines. I have my suspicions of the PaintPrivate() method in the implementation of DataGridViewTextBoxCell(), so if you're feeling frisky, maybe put a microscope to it. You'll need an IL disassembler to see this stuff that's not exposed publicly. Specifically, this part of the code I have suspicions of:
if (text != null && (paint && !flag2 || computeContentBounds))
{
int y = cellStyle.WrapMode == DataGridViewTriState.True ? 1 : 2;
rectangle3.Offset(0, y);
// ISSUE: explicit reference operation
// ISSUE: variable of a reference type
Rectangle& local = #rectangle3;
// ISSUE: explicit reference operation
int width = (^local).Width;
// ISSUE: explicit reference operation
(^local).Width = width;
rectangle3.Height -= y + 1;
if (rectangle3.Width > 0 && rectangle3.Height > 0)
{
TextFormatFlags cellStyleAlignment = DataGridViewUtilities.ComputeTextFormatFlagsForCellStyleAlignment(this.DataGridView.RightToLeftInternal, cellStyle.Alignment, cellStyle.WrapMode);
if (paint)
{
if (DataGridViewCell.PaintContentForeground(paintParts))
{
if ((cellStyleAlignment & TextFormatFlags.SingleLine) != TextFormatFlags.Default)
cellStyleAlignment |= TextFormatFlags.EndEllipsis;
TextRenderer.DrawText((IDeviceContext) graphics, text, cellStyle.Font, rectangle3, flag3 ? cellStyle.SelectionForeColor : cellStyle.ForeColor, cellStyleAlignment);
}
}
else
rectangle1 = DataGridViewUtilities.GetTextBounds(rectangle3, text, cellStyleAlignment, cellStyle);
}
Sorry for the book!
TL;DR USE A SMALL ASS FONT IF YOU WANT TO PACK CHARACTERS INTO HUGE CELLS.
I'm using the regular System.Windows.Form.RichTextBox control for a WinForm application running on the .NET Framework 2.0 to show a status log. Since the Form and several other child controls, have AutoSize=True, the application does not always look the same way on different setups. I have no way to know in advance the exact size of the control and anyway I guess there are some implications related to the ratio (font appearence)/(gui dimensions) of each particular configuration.
So now let's depict the most dynamic scenario. I want to know what's the exact maximum length of the string, a given RichTextBox can show on the same line (without exceeding the border nor word wrapping) where such a RichTextBox is using a generic and known, monospaced font and size.
In case there's no any straightforward way to accomplish this result, does anyway know if I may use any kind of trick like injecting an incrementally growing test string till some weird event gets fired?
That's what I got till now. I used the TextRenderer class and the strategy I anticipated on my question above. Of course it makes sense only if the control uses a monospaced font. Despite it works for my problem, I'm still curious to know if anyone knows a better way to reach the same goal. So the question will still be open for a while.
int maxStringLength = GetMaxStringLengthPerLine(myRichTextBox);
int GetMaxStringLengthPerLine(RichTextBox textbox) {
return GetMaxStringLength(textbox.Size.Width, textbox.Font);
}
int GetMaxStringLength(int width, Font font) {
int i = 0;
while(TextRenderer.MeasureText(new string('A',++i), font).Width<=width);
return --i;
}
I'm trying to use the watermark plugin to write text on images for my project. Right now I'm trying to find out how to set a "width" for a writing box so I can get automatic line returns. Is there a way to do this with the watermark plugin?
Also I'm trying to see if I can get a "text-align: center" effect when I'm writing my text (possibliy in relation to that set width), how could I get that setup?
I'm thinking that the alternative to this would be to have code driven line returns and centering, but this would mean that I would have to count the width of my characters and this seems like a world of pain hehe
Here is a code sample that shows what I'm doing (this currently works):
var c = Config.Current;
var wp = c.Plugins.Get<WatermarkPlugin>();
var t = new TextLayer();
t.Text = panty.Message;
t.TextColor = (System.Drawing.Color) color;
t.Font = fonts[myFunObject.Font];
t.FontSize = fontSize[myFunObject.LogoPosition];
t.Left = new DistanceUnit(5, DistanceUnit.Units.Pixels);
t.Top = new DistanceUnit(5, DistanceUnit.Units.Pixels);
wp.NamedWatermarks["myFunObjectMessage"] = new Layer[] { t };
EDIT: I also have to mention that the text I'm writing is user submitted so it's different everytime. If you want a similar case, think about thos funny cat images with funny text captions on them. This project is quite similar to that. (Minus the cats)
Thanks for the help!
Basically, System.Drawing (and therefore the current version of Watermark) are very primitive about line wrapping.
As you mentioned, you can do hacky stuff with character counting and separate MeasureString calls with loops, but the results are only barely acceptable.
You may try to fork the Watermark source code and hack support for your use case. I don't see a way to improve Watermark in a generic way without replacing the underlying graphics engine first (which may happen anyway).
System.Drawing has unsurpassed image resampling quality. Text wrapping, though, it kind of stinks at.