iText -- How do I get the rendered dimensions of text? - itext

I would like to find out information about the layout of text in a PdfPCell. I'm aware of BaseFont.getWidthPointKerned(), but I'm looking for more detailed information like:
How many lines would a string need if rendered in a cell of a given width (say, 30pt)? What would the height in points of the PdfPCell be?
Give me the prefix or suffix of a string that fits in a cell of a given width and height. That is, if I have to render the text "Today is a good day to die" in a specific font in a PdfPCell of width 12pt and height 20pt, what portion of the string would fit in the available space?
Where does iText break a given string when asked to render it in a cell of a given width?
This is with regard to iText 2.1.6. Thanks.

iText uses the ColumnText class to render content to a cell. This is explained in my book on page 98-99. This means that, just like with ColumnText, you need to make the distinction between text mode and composite mode.
In any case, ColumnText measures the width of the characters and tests if they fit the available width. If not, the text is split. You can change the split behavior in different ways: by introducing hyphenation or by defining a custom split character.
I've written a small proof of concept to show how you could implement custom "truncation" behavior. See the TruncateTextInCell example.
Instead of adding the content to the cell, I have an empty cell for which I define a cell event. I pass the long text "D2 is a cell with more content than we can fit into the cell." to this event.
In the event, I use a fancy algorithm: I want the text to be truncated in the middle and insert "..." at the place where I truncated the text.
BaseFont bf = BaseFont.createFont();
Font font = new Font(bf, 12);
float availableWidth = position.getWidth();
int contentLength = content.length();
int leftChar = 0;
int rightChar = contentLength - 1;
availableWidth -= bf.getWidthPoint("...", 12);
while (leftChar < contentLength && rightChar != leftChar) {
availableWidth -= bf.getWidthPoint(content.charAt(leftChar), 12);
if (availableWidth > 0)
leftChar++;
else
break;
availableWidth -= bf.getWidthPoint(content.charAt(rightChar), 12);
if (availableWidth > 0)
rightChar--;
else
break;
}
String newContent = content.substring(0, leftChar) + "..." + content.substring(rightChar);
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText ct = new ColumnText(canvas);
ct.setSimpleColumn(position);
ct.addElement(new Paragraph(newContent, font));
ct.go();
As you can see, we get the available width from the position parameter and we check how many characters match, alternating between a character at the start and a character at the end of the content.
The result is shown in the resulting PDF: the content is truncated like this: "D2 is a c... the cell."
Your question about "how many lines" can be solved in a similar way. The ColumnText class has a getLinesWritten() method that gives you that information. You can find more info about positioning a ColumnText object in my answer to your other question: Can I tell iText how to clip text to fit in a cell

Related

how to let long text change to multiple lines when adding annotation to images

how to let long text change to multiple lines when adding annotation to image
and make the length of each line are equal, like rectangle?
image temp:=getfrontimage()
temp.ShowImage()
imageDisplay disp = front.ImageGetImageDisplay(0)
getsize(temp,x,y)
le=x*2/3
to1=y*80/100
component text1 = NewTextAnnotation(le,to1,string1+","+string2+","+string3,100)
I tried to add 3 strings to an image, each string has more than 15 letters/characters, Total more than 50 letters.
If I put all 3 strings in one text annotation in on line, it is too long.
If I put them as 3 text annotations, as the each line does not have exactly same numbers of letters, it shows ugly.
Is there any could let the text as multiple line, and the background of texts in each line has the same length?
Or the 3 text annotations has the same length, I mean the background of the texts has the same length, when the letters in each text annotations are not same, for example, 1st text annotation with 16 letters, 2nd text annotation with 20 letters, 3rd text annotation with 14 letters, but their background of the text have the same length.
Thanks,
You can add line-breaks as with all strings by simply adding the line-break escape string \n.
Example script:
number sx = 512
number sy = 512
image img := RealImage("test",4,sx,sy)
img = icol
img.ShowImage()
imageDisplay disp = img.ImageGetImageDisplay(0)
number l = sx * 2/3
number t = sy * 80/100
String mLstr = "Some text line\nSome more text lines\nShort text"
number fontSize = 12
Component Line = disp.NewTextAnnotation(l,t,mLstr,fontSize)
Line.TextAnnotationSetAlignment(1) // 1=Left, 2=Center, 3=Right
Line.ComponentSetDrawingMode(1) // 1=with background, 2=without background
Line.ComponentSetBackgroundColor(0.5,0.0,0)
Line.ComponentSetForegroundColor(0,1,0)
disp.ComponentAddChildAtEnd(line)
A note: When creating the new component, there are two different variants of the NewTextAnnotation command:
Component NewTextAnnotation( Component ref_par_comp, Number left, Number top, String text, Number size )
Component NewTextAnnotation( Number left, Number top, String text, Number size )
The first one takes the addtional "parent" component. If you use that one, then the font-size will scale with the default display-size of the parent component on the screen, i.e. will not be different for differently sizes images.
To test: Just try the above script with sx and sy values. Then do the same without the disp. in the line-annotation creating line.

"Best fit" text option to shrink only

Is there an easy way to dynamically resize a text to fit its contents, not exceeding certain maximum size? I mean, something like one-way "best fit" option, one that shrinks only.
I tried to manipulate the size of the best-fit text by script, but that doesn't do anything:
private void ModifyText(Text text, string str, int maxSize)
{
text.text = str;
if (text.fontSize > maxSize) text.fontSize = maxSize;
}
Best fit lets you define minimum and maximum font sizes, right in the inspector

Changing text line spacing

I'm creating a PDF document consisting of text only, where all the text is the same point size and font family but each character could potentially be a different color. Everything seems to work fine using the code snippet below, but the default space between the lines is slightly greater than I consider ideal. Is there a way to control this? (FYI, type "ColoredText" in the code below merely contains a string and its color. Also, the reason I am treating the newline character separately is that for some reason it doesn't cause a newline if it's in a Chunk.)
Thanks,
Ray
List<byte[]> pdfFilesAsBytes = new List<byte[]>();
iTextSharp.text.Document document = new iTextSharp.text.Document();
MemoryStream memStream = new MemoryStream();
iTextSharp.text.pdf.PdfWriter.GetInstance(document, memStream);
document.SetPageSize(isLandscape ? iTextSharp.text.PageSize.LETTER.Rotate() : iTextSharp.text.PageSize.LETTER);
document.Open();
foreach (ColoredText coloredText in coloredTextList)
{
Font font = new Font(Font.FontFamily.COURIER, pointSize, Font.NORMAL, coloredText.Color);
if (coloredText.Text == "\n")
document.Add(new Paragraph("", font));
else
document.Add(new Chunk(coloredText.Text, font));
}
document.Close();
pdfFilesAsBytes.Add(memStream.ToArray());
According to the PDF specification, the distance between the baseline of two lines is called the leading. In iText, the default leading is 1.5 times the size of the font. For instance: the default font size is 12 pt, hence the default leading is 18.
You can change the leading of a Paragraph by using one of the other constructors. See for instance: public Paragraph(float leading, String string, Font font)
You can also change the leading using one of the methods that sets the leading:
paragraph.SetLeading(fixed, multiplied);
The first parameter is the fixed leading: if you want a leading of 15 no matter which font size is used, you can choose fixed = 15 and multiplied = 0.
The second parameter is a factor: for instance if you want the leading to be twice the font size, you can choose fixed = 0 and multiplied = 2. In this case, the leading for a paragraph with font size 12 will be 24, for a font size 10, it will be 20, and son on.
You can also combine fixed and multiplied leading.
private static Paragraph addSpace(int size = 1)
{
Font LineBreak = FontFactory.GetFont("Arial", size);
Paragraph paragraph = new Paragraph("\n\n", LineBreak);
return paragraph;
}

Add rectangle as inline-element with iText

How do I add a rectangle (or other graphical elements) as inline-elements to an iText PDF?
Example code of what I'm trying to achieve:
foreach (Row r in entrylist)
{
p = new Paragraph();
p.IndentationLeft = 10;
p.SpacingBefore = 10;
p.SpacingAfter = 10;
p.Add(new Rectangle(0, 0, 10, 10)); <<<<<<<<< THAT ONE FAILS
p.Add(new Paragraph(r.GetString("caption"), tahoma12b));
p.Add(new Paragraph(r.GetString("description"), tahoma12));
((Paragraph)p[1]).IndentationLeft = 10;
doc.Add(p);
}
It's something like a column of text-blocks, of which each of them have (only a printed) checkbox.
I've tried various things with DirectContent, but it requires me to provide absolute X and Y values. Which I simply don't have. The elements should be printed at the current position, wherever that may be.
Any clues?
You need a Chunk for which you've defined a generic tag. For instance, in this example listing a number of movies, a snippet of pellicule is drawn around the year a movie was produced and an ellipse was drawn in the background of the link to IMDB.
If you look at the MovieYears example, you'll find out how to use the PdfPageEvent interface and its onGenericTag() method. You're right that you can't add a Rectangle to a Paragraph (IMHO that wouldn't make much sense). As you indicate, you need to draw the rectangle to the direct content, and you get the coordinates of a Chunk by using the setGenericTag() method. As soon as the Chunk is drawn on the page, its coordinates will be passed to the onGenericTag() method.

Relative UILabel in a game object

I created a game object which acts as a repeating item for a UIGrid which I populate dynamically. The gameobject (RowItem) has couple of UILabel whose text can change on runtime depending on the content. The content of these UILabels overlap when the text is bigger. Can anybody help me in how to make UILabel expand relative to the adjacent UILabel when the text is more/less?
You can use transform.localScale property of the UILabel's property to scale it. Just make them bigger when the text is bigger than let's say 20 characters. Try with arbitrary values.
Also when you change the scale, run a re-align method, which aligns other labels so that they don't overlap.
you can get the text length in pixel by this:
UILabel label;
float width = label.relativeSize.x * label.transform.localScale.x;
float height = label.relativeSize.y * label.transform.localScale.y;
Let's say that you want to set you max length to 100, you can do this:
if (width > 100)
{
label.localScale = new Vector3(100 / label.relativeSize.x, 100/ label.relativeSize.x, 1);
}
the second param for Vector3 is also based on relativeSize.x is not a typo, that makes sure your text will not become thin.
Hope this works.