How to add inline spacing in pdfPCell - itext

I need to add Space between two lines in iTextSharp pdfPCell
Chunk chunk = new Chunk("Received Rs(In Words) : " + " " + myDataTable.Tables[1].Rows[0]["Recieved"].ToString(), font8);
PdfPTable PdfPTable = new PdfPTable(1);
PdfPCell PdfPCell =new PdfPCell(new Phrase(Chunk ));
PdfPCell .Border = PdfCell.NO_BORDER;
PdfPTable .AddCell(PdfPCell );

Please take a look at the following screen shot:
Based on your code snippet, I assume that you want to separate "Received Rs (in Words):" from "Priceless", but it's not clear to me what you want to happen if there is more than one line, so I have written 3 examples:
Example 1:
table = new PdfPTable(2);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
table.setWidthPercentage(60);
table.setSpacingAfter(20);
cell = new PdfPCell(new Phrase("Received Rs (in Words):"));
cell.setBorder(PdfPCell.LEFT | PdfPCell.TOP | PdfPCell.BOTTOM);
table.addCell(cell);
cell = new PdfPCell(new Phrase("Priceless"));
cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
cell.setBorder(PdfPCell.RIGHT | PdfPCell.TOP | PdfPCell.BOTTOM);
table.addCell(cell);
document.add(table);
In this example, I put "Received Rs (in Words):" and "Priceless" in two different cells, and I align the content of the first cell to the left and the content of the second cell to the right. This creates space between the two Chunks.
Example 2
// same code as above, except for:
table.setWidthPercentage(50);
I decreased the width of the table to show you what happens if some content doesn't fit a cell. As we didn't define any widths for the columns, the two columns will have an equal width, but as "Received Rs (in Words):" needs more space than "Priceless", the text doesn't fit the width of the cell and it is wrapped. We could avoid this, by defining a larger with for the first column when compared to the second column.
Example 3:
table = new PdfPTable(1);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
table.setWidthPercentage(50);
Phrase p = new Phrase();
p.add(new Chunk("Received Rs (In Words):"));
p.add(new Chunk(new VerticalPositionMark()));
p.add(new Chunk("Priceless"));
table.addCell(p);
document.add(table);
This example is very close to what you have, but instead of introducing space characters to create space, I introduce a special chunk: new VerticalPositionMark()). This chunk will separate the two parts of the Phrase by introducing as much space as possible.
If this doesn't answer your question, you were probably looking for the concept known as leading. Leading is the space between the baseline of two lines of text. If that is the case, please read the following Q&As:
Changing text line spacing
Spacing/Leading PdfPCell's elements
Paragraph leading inside table cell
Adding more text to a cell in table in itext
How to maintain indentation if a paragraph takes new line in PdfPCell?
If your question isn't about leading, then maybe you're just looking for the concept known as non-breaking space:
How to use non breaking space in iTextSharp
Generating pdf file using Itext

Related

iText(Sharp) - Text is different when drawn with cell event vs. directly

I've got a PdfPTable in which I am drawing simple text:
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
Font f2 = new Font(bf, 10.0f);
PdfPTable tab = new PdfPTable(2);
table.AddCell(new PdfPCell(new Phrase("Dude", f2)));
And that's all fine and dandy. But then in order to do some fancier stuff, I'm trying to get cell events to work:
Font f2 = new Font(bf, 10.0f); // Pretend this is a global
class CellEvent : IPdfPCellEvent
{
void IPdfPCellEvent.CellLayout(PdfPCell cell, Rectangle r, PdfContentByte[] canvases)
{
ColumnText ct = new ColumnText(canvases[0]);
ct.SetSimpleColumn(r);
ct.AddElement(new PdfPCell(new Phrase("Dude", f2)));
ct.Go();
}
}
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfPTable tab = new PdfPTable(2);
PdfPCell ce = new PdfPCell();
ce.CellEvent = new CellEvent();
table.AddCell(ce);
When I do this though, the cell is drawn quite differently. My actual text is multiple lines long, and when drawn directly (adding the phrase directly to the cell) the text lines are quite close together vertically; when drawn via the cell event, there is a lot of space between the text lines and it doesn't fit in the box the PdfPTable provides for me.
Is there a different, more preferred method for drawing text inside IPdfPCellEvent.CellLayout()? Or are there just some formatting parameters I need to copy from PdfPCell into ColumnText?
There is something very wrong with this snippet:
ColumnText ct = new ColumnText(canvases[0]);
ct.SetSimpleColumn(r);
ct.AddElement(new PdfPCell(new Phrase("Dude", f2)));
ct.Go();
More specifically:
ct.AddElement(new PdfPCell(new Phrase("Dude", f2)));
You can not use the PdfPCell object outside of the context of a PdfPTable.
As for the differences between content in PdfPCell and ColumnText, you may want to read the answers to these questions:
itext ColumnText ignores alignment
Right aligning text in PdfPCell
The content of a PdfPCell is actually stored in a ColumnText object, but a PdfPCell may have a padding.
There's also text mode versus composite mode. You are talking about the distance between two lines. In text mode, this distance is defined at the level of the PdfPCell/ColumnText using the setLeading() method. In composite mode, this parameter is ignored. Instead, the leading of the elements added to the PdfPCell/ColumnText is used.
For instance: if p1, p2 and p3 are three Paragraph objects, each having a different leading, then ct will have text with three different leadings if you do this:
ct.addElement(p1);
ct.addElement(p2);
ct.addElement(p3);

How to align a label versus its content?

I have a label (e.g. "A list of stuff") and some content (e.g. an actual list). When I add all of this to a PDF, I get:
A list of stuff: test A, test B, coconut, coconut, watermelons, apple, oranges, many more
fruites, carshow, monstertrucks thing
I want to change this so that the content is aligned like this:
A list of stuff: test A, test B, coconut, coconut, watermelons, apple, oranges, many more
fruites, carshow, monstertrucks thing, everything is startting on the
same point in the line now
In other words: I want the content to be aligned so that it every line starts at the same X position, no matter how many items are added to the list.
There are many different ways to achieve what you want: Take a look at the following screen shot:
This PDF was created using the IndentationOptions example.
In the first option, we use a List with the label ("A list of stuff: ") as the list symbol:
List list = new List();
list.setListSymbol(new Chunk(LABEL));
list.add(CONTENT);
document.add(list);
document.add(Chunk.NEWLINE);
In the second option, we use a paragraph of which we use the width of the LABEL as indentation, but we change the indentation of the first line to compensate for that indentation.
BaseFont bf = BaseFont.createFont();
Paragraph p = new Paragraph(LABEL + CONTENT, new Font(bf, 12));
float indentation = bf.getWidthPoint(LABEL, 12);
p.setIndentationLeft(indentation);
p.setFirstLineIndent(-indentation);
document.add(p);
document.add(Chunk.NEWLINE);
In the third option, we use a table with columns for which we define an absolute width. We use the previously calculated width for the first column, but we add 4, because the default padding (left and right) of a cell equals 2. (Obviously, you can change this padding.)
PdfPTable table = new PdfPTable(2);
table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
table.setTotalWidth(new float[]{indentation + 4, 519 - indentation});
table.setLockedWidth(true);
table.addCell(LABEL);
table.addCell(CONTENT);
document.add(table);
There may be other ways to achieve the same result, and you can always tweak the above options. It's up to you to decide which option fits best in your case.

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

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

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;
}

Setting Alignment for each Element when more than one Element added to a PDFPcell

In a table, I have a few cells that contain multiple elements. For Example, to indicate address , the cell may contain a phrase containing an "ADDRESS:" header Chunk followed by another chunk containing the actual address:
FROM: -- Chunk 1 in Phrase
123 Main St, Some City, ST -- Chunk 2 in Phrase
As of now, to align the cell contents, I am using the following code in the PDFPcell:
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
However, this aligns all of the cell contents to the middle of the cell. If I want to put Chunk 1 at TOP_LEFT and Chunk 2 at BOTTOM_LEFT, is it possible to achieve it with iTextSharp? Essentially, I am looking for a way to align various elements within a cell at different locations.
Unfortunately the only way to do what you want is to add a sub-table in place of your multiple chunks.
t.AddCell("Row 1");
PdfPTable subTable = new PdfPTable(1);
subTable.DefaultCell.VerticalAlignment = Element.ALIGN_TOP;
subTable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT;
subTable.AddCell("Top Align");
subTable.DefaultCell.VerticalAlignment = Element.ALIGN_BOTTOM;
subTable.DefaultCell.HorizontalAlignment = Element.ALIGN_RIGHT;
subTable.AddCell("Bottom Align");
t.AddCell(subTable);
doc.Add(t);