Itextsharp V 5.x:image cell height in pdfptable - itext

I am creating table and adding cells to table with text or image content.
var pdfTable = new PdfPTable(2);
nCell = new PdfPCell(new Phrase("A")) {HorizontalAlignment = 1};
pdfTable.AddCell(nCell);
pdfTable.AddCell("B");
pdfTable.AddCell(qrImg);
pdfTable.AddCell(image39);
pdfTable.AddCell("C");
pdfTable.AddCell("D");
pdfTable.SpacingBefore = 20f;
pdfTable.SpacingAfter = 30f;
document.Add(pdfTable);
renders 3 rows and displays image in row2
if I add cells by creating pdfpcell object first:
var cell = new PdfPCell(qrImg};
pdfTable.AddCell(nCell);
only rows 1 and 3 are visible.
If I add height property to cell then the image gets diaplayed.
my questions ( 3 but related);
is it required for us to specify height when adding cell with image ( cells added with text content - phrase resenders correctly) ?
Is there something I am missing when creating a new cell, which prevents images to be rendered?
should I always be using Addcell(image) when adding image content?
Thank you all,
Mar

Its easier to understand what's going on if you browse the source. A table within iText keeps a property around called DefaultCell that gets reused over and over. This is done so that the basic cell properties are kept from cell to cell. When you call AddCell(Image) the DefaultCell's image is set to the image, then added to the table, and finally the image get's null'd out.
543 defaultCell.Image = image;
544 AddCell(defaultCell);
545 defaultCell.Image = null;
The PdfCell(Image) constructor actually internally calls an overload PdfPCell(Image, bool) and passes false as the second parameter, fit. Here's the constructor's conditional on fit:
152 if (fit) {
153 this.image = image;
154 Padding = borderWidth / 2;
155 }
156 else {
157 column.AddText(this.phrase = new Phrase(new Chunk(image, 0, 0, true)));
158 Padding = 0;
159 }
If you pass false to fit, which is the default, you'll see that the image is added in a much more complicated way.
So basically you can add an image in three main ways (okay, lots more actually if you use nested tables or chunks or phrases), the first below picks up the defaults and is probably what you want. The second is more raw but gets you closer to what you probably want. The third is the most raw and assumes that you know what you're doing.
var qrImg = iTextSharp.text.Image.GetInstance(sampleImage1);
//Use the DefaultCell, including any existing borders and padding
pdfTable.AddCell(qrImg);
//Brand new cell, includes some padding to get the image to fit
pdfTable.AddCell(new PdfPCell(qrImg, true));
//Brand new cell, image added as a Chunk within a Phrase
pdfTable.AddCell(new PdfPCell(qrImg));

Related

iText 7 - text overlay in a table, how to span over all possible columns

there is a picture visualizing my problem.
I have a table with let's say 5 columns and 5 rows. The first row and first column has a long text. The text won't fit in to the cell but I want to show the entire text in a line, spanning all the following columns.
It is not a real colspan as the column-borders should still be visible. So it's more an overlay.
I am experimenting with the example "Fit text in cell" with the custom cell renderer but I don't really understand the different occupied areas, boxes and the dimensions coming with it.
Not to say that the dimension and positioning thing in iText is not really intuitive.
I appreciate any help.
Thanks.
So you want something like this ?
C# example
//Create a table with 5 columns
var table = new Table(new float[] { 3,3,3,3,3}).SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout();
// Creat the cell with the long text
Cell cell = new Cell(1, 5).Add(new Paragraph("Long text that spans over the 5 Columns"));
//Add the top row 5 cells
table.AddCell("Column 1 text")
table.AddCell("Column 2 text")
table.AddCell("Column 3 text")
table.AddCell("Column 4 text")
table.AddCell("Column 5 text")
//Add the long text
table.AddCell(cell);

Footer image printed twice when printing certificates in iText

When we print certificate all most print in certificate but footer image is printing twice. I am using Pdfptable for printing footer image.
table = new PdfPTable(1);
int footerWidth[] = {100};
table.setWidths(footerWidth);
table.setWidthPercentage(100);
Image image2 = Image.getInstance("footerImage.jpg");
cell = new PdfPCell(image2,true);
cell.setBorder(0);
table.setTotalWidth(document.getPageSize().width()-document.leftMargin()-document.rightMargin());
table.addCell(cell);
//write the footer
table.writeSelectedRows(0, -1, document.leftMargin(), table.getTotalHeight()+document.bottomMargin(), writer.getDirectContent());
EventLog.write(appName,"done adding footer",logFile);
document.add(table);
Your table is added twice because you add it twice.
You add it a first time when you use writeSelectedRows():
table.writeSelectedRows(0, -1, document.leftMargin(), table.getTotalHeight()+document.bottomMargin(), writer.getDirectContent());
This adds the table at a very specific position defined by the coordinates:
x = document.leftMargin();
y = table.getTotalHeight()+document.bottomMargin();
You add the table a second time, when you do this:
document.add(table);
This adds the table at whichever position the page cursor is at, which is usually immediately after the previous content that was added with a document.add() method.
PS:
Headers and footers are usually added in an OnEndPage() page event. You're adding the footer only once. You may want to use page events to add the footer on every page.

How to add inline spacing in pdfPCell

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

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

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