How to tell PdfPTable that PdfPCells need to be showed dynamically according to free space on PdfPTable - pdf

I have this PDF document that I made with iText in Java.
The PDF Document contains data that is added via PDFPTable objects.
The 'Problem' is that when I have more data then fits on one PDF page, the data is rendered on the next page, leaving me with empty space on the first page. (See the image 'Problem' side).
I would like to have these empty spaces filled with 'PDFPCell' object, see 'Solution' (these PdfPCell object contain another PdfPTable, the data in this PdfPTable must not be 'continued' on the next page of the pdf when it does not fit).
This is a small example in code:
PdfPTable outerTable = new PdfPTable(1);
outerTable.setHorizontalAlignment(Element.ALIGN_LEFT);
outerTable.setWidthPercentage(100);
int i = 0;
while (i < 5)
{
i++;
PdfPTable innerTable = new PdfPTable(new float[] {0.25f, 0.25f, 0.25f, 0.25f});
innerTable .setHorizontalAlignment(Element.ALIGN_LEFT);
innerTable .setWidthPercentage(100);
PdfPCell cell = new PdfPCell(innerTable);
cell.setPadding(0);
innerTable.addCell(new Phrase("test Data"));
innerTable.addCell(new Phrase("test Data"));
innerTable.addCell(new Phrase("test Data"));
innerTable.addCell(new Phrase("test Data"));
outerTable.addCell(cell);
}
document.add(outertable);
document.close();

Please take a look at the DropTablePart example. In this example, I add 4 tables with 19 rows to a ColumnText object. As soon as a table doesn't fit the page, I drop the remaining content of the ColumnText object (which will automatically drop the rest of the table) and I start a new page where a new table will start.
Dropping the content of the ColumnText object can be done in two different ways:
Either:
ct = new ColumnText(writer.getDirectContent());
Or:
ct.setText(null);
The result looks like this:
As you can see, rows 10-18 are dropped from inner table 3.
This is the full code:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
Rectangle column = new Rectangle(36, 36, 559, 806);
ColumnText ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(column);
for (int i = 0; i < 4; ) {
PdfPTable table = new PdfPTable(new float[]{0.25f, 0.25f, 0.25f, 0.25f});
table.setHorizontalAlignment(Element.ALIGN_LEFT);
table.setWidthPercentage(100);
PdfPCell cell = new PdfPCell(new Phrase("inner table " + (++i)));
cell.setColspan(4);
table.addCell(cell);
for (int j = 0; j < 18; j++) {
table.addCell(new Phrase("test Data " + (j + 1) + ".1"));
table.addCell(new Phrase("test Data " + (j + 1) + ".1"));
table.addCell(new Phrase("test Data " + (j + 1) + ".1"));
table.addCell(new Phrase("test Data " + (j + 1) + ".1"));
}
ct.addElement(table);
if (ColumnText.hasMoreText(ct.go())) {
document.newPage();
ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(column);
}
}
document.close();
}
I didn't use nested tables, because it is generally a bad idea to use nested tables. It has a negative impact on the performance of your application and it usually results in code that is hard to maintain (the programmers who inherit our application will thank you for not using nested tables).

Related

Automatic PDF Rendering

I've read the MigraDoc/PdfSharp documentation, but it feels a bit thin. I want to render out a PDF, but not have to manually specify width and height. I just want it to align right, center, or left (of margins), and handle all the sizing for me.
Public Sub Write()
Dim document As PdfDocument = New PdfDocument()
Dim page As PdfPage = document.AddPage()
Dim gfx As XGraphics = XGraphics.FromPdfPage(page)
gfx.MUH = PdfFontEncoding.Unicode
gfx.MFEH = PdfFontEmbedding.Default
Dim font As XFont = New XFont("Verdana", 13, XFontStyle.Bold)
Dim migraDocument As New Document
Dim sec As Section = migraDocument.AddSection()
Dim quotationHeader As New Paragraph
quotationHeader.AddText("Quotation" & vbNewLine)
quotationHeader.Format.Alignment = ParagraphAlignment.Right
sec.Add(quotationHeader)
Dim dhAddressInfo As New Paragraph
dhAddressInfo.AddText("ADDRESS GOES HERE")
dhAddressInfo.Format.Alignment = ParagraphAlignment.Left
sec.Add(dhAddressInfo)
Dim quotationInfo As New Paragraph
quotationInfo.AddText("QUOTATION INFO AND DATE HERE")
quotationInfo.Format.Alignment = ParagraphAlignment.Right
sec.Add(quotationInfo)
Dim customerBilling As New Paragraph
With Customer
customerBilling.AddText("CUSTOMER BILLING OBJECT PROPERTIES HERE")
End With
customerBilling.Format.Alignment = ParagraphAlignment.Left
sec.Add(customerBilling)
Dim authorInfo As New Paragraph
authorInfo.AddText("AUTHOR INFO HERE")
authorInfo.Format.Alignment = ParagraphAlignment.Right
sec.Add(authorInfo)
Dim pricingTable As New Table
'pricingTable.Format.Alignment = ParagraphAlignment.Center
pricingTable.AddColumn("13cm")
pricingTable.AddColumn("13cm")
Dim headerRow As New Row
headerRow = pricingTable.AddRow()
headerRow.HeadingFormat = True
headerRow.Cells(0).AddParagraph("Description")
headerRow.Cells(1).AddParagraph("Amount")
For i As Integer = 0 To SelectedPrices.Count - 1
Dim row As Row = pricingTable.AddRow()
Dim price As Pricing = SelectedPrices(i)
row.Cells(0).AddParagraph(price.Item)
row.Cells(1).AddParagraph(price.Price * price.Quantity)
Next
Dim totalRow As Row = pricingTable.AddRow()
totalRow.Cells(0).AddParagraph("Total: ")
Dim total As Double = 0
For Each price As Pricing In SelectedPrices
total = total + (price.Price * price.Quantity)
Next
totalRow.Cells(1).AddParagraph(total.ToString)
sec.Add(pricingTable)
Dim docRenderer As DocumentRenderer = New DocumentRenderer(migraDocument)
docRenderer.PrepareDocument()
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(0), XUnit.FromCentimeter(0), "10cm", quotationHeader)
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(0), XUnit.FromCentimeter(2), "10cm", dhAddressInfo)
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(5), XUnit.FromCentimeter(2), "10cm", quotationInfo)
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(0), XUnit.FromCentimeter(6), "10cm", customerBilling)
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(5), XUnit.FromCentimeter(6), "10cm", authorInfo)
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(3), XUnit.FromCentimeter(10), "10cm", pricingTable)
document.Save(Environment.CurrentDirectory & "\test.pdf")
End Sub
Notice at the bottom I'm specifying the X and Y coordinates of each section. I just want to define spacing. Alignment should take care of the rest.
I found a different tutorial that uses PdfDocumentRenderer and shows how to correctly use it. It's not in VB, but quite easily translated. I copied it below in case the link goes dead.
http://www.c-sharpcorner.com/UploadFile/aftab_ku/create-object-model-document-and-renders-them-into-pdf/
public Document CreateDocument()
{
// Create a new MigraDoc document
this.document = new Document();
this.document.Info.Title = "";
this.document.Info.Subject = "";
this.document.Info.Author = "Aftab";
DefineStyles();
CreatePage();
FillContent();
return this.document;
}
Here, CreateDocument() in PDFform.cs creates a new MigraDoc. Take a look at the three functions called for creating style and page and fill the content of the tables.
//
void DefineStyles()
{
// Get the predefined style Normal.
Style style = this.document.Styles["Normal"];
// Because all styles are derived from Normal, the next line changes the
// font of the whole document. Or, more exactly, it changes the font of
// all styles and paragraphs that do not redefine the font.
style.Font.Name = "Verdana";
style = this.document.Styles[StyleNames.Header];
style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right);
style = this.document.Styles[StyleNames.Footer];
style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center);
// Create a new style called Table based on style Normal
style = this.document.Styles.AddStyle("Table", "Normal");
style.Font.Name = "Verdana";
style.Font.Name = "Times New Roman";
style.Font.Size = 9;
// Create a new style called Reference based on style Normal
style = this.document.Styles.AddStyle("Reference", "Normal");
style.ParagraphFormat.SpaceBefore = "5mm";
style.ParagraphFormat.SpaceAfter = "5mm";
style.ParagraphFormat.TabStops.AddTabStop("16cm", TabAlignment.Right);
}
DefineStyles() does the job of styling the document:
void CreatePage()
{
// Each MigraDoc document needs at least one section.
Section section = this.document.AddSection();
// Put a logo in the header
Image image= section.AddImage(path);
image.Top = ShapePosition.Top;
image.Left = ShapePosition.Left;
image.WrapFormat.Style = WrapStyle.Through;
// Create footer
Paragraph paragraph = section.Footers.Primary.AddParagraph();
paragraph.AddText("Health And Social Services.");
paragraph.Format.Font.Size = 9;
paragraph.Format.Alignment = ParagraphAlignment.Center;
............
// Create the item table
this.table = section.AddTable();
this.table.Style = "Table";
this.table.Borders.Color = TableBorder;
this.table.Borders.Width = 0.25;
this.table.Borders.Left.Width = 0.5;
this.table.Borders.Right.Width = 0.5;
this.table.Rows.LeftIndent = 0;
// Before you can add a row, you must define the columns
Column column;
foreach (DataColumn col in dt.Columns)
{
column = this.table.AddColumn(Unit.FromCentimeter(3));
column.Format.Alignment = ParagraphAlignment.Center;
}
// Create the header of the table
Row row = table.AddRow();
row.HeadingFormat = true;
row.Format.Alignment = ParagraphAlignment.Center;
row.Format.Font.Bold = true;
row.Shading.Color = TableBlue;
for (int i = 0; i < dt.Columns.Count; i++)
{
row.Cells[i].AddParagraph(dt.Columns[i].ColumnName);
row.Cells[i].Format.Font.Bold = false;
row.Cells[i].Format.Alignment = ParagraphAlignment.Left;
row.Cells[i].VerticalAlignment = VerticalAlignment.Bottom;
}
this.table.SetEdge(0, 0, dt.Columns.Count, 1, Edge.Box,
BorderStyle.Single, 0.75, Color.Empty);
}
Here CreatePage() adds a header, footer, and different sections into the document and then the table is created to display the records. Columns from the datatable are added into the table inside the document and then a header row that contains the column names is added.
column = this.table.AddColumn(Unit.FromCentimeter(3));
//creates a new column and width of the column is passed as a parameter.
Row row = table.AddRow();
//A new header row is created
row.Cells[i].AddParagraph(dt.Columns[i].ColumnName);
//this will add the column name to header of the row.
this.table.SetEdge(0, 0, dt.Columns.Count, 1, Edge.Box,
BorderStyle.Single, 0.75, Color.Empty);
//sets the border of the row
void FillContent()
{
...............
Row row1;
for (int i = 0; i < dt.Rows.Count; i++)
{
row1 = this.table.AddRow();
row1.TopPadding = 1.5;
for (int j = 0; j < dt.Columns.Count; j++)
{
row1.Cells[j].Shading.Color = TableGray;
row1.Cells[j].VerticalAlignment = VerticalAlignment.Center;
row1.Cells[j].Format.Alignment = ParagraphAlignment.Left;
row1.Cells[j].Format.FirstLineIndent = 1;
row1.Cells[j].AddParagraph(dt.Rows[i][j].ToString());
this.table.SetEdge(0, this.table.Rows.Count - 2, dt.Columns.Count, 1,
Edge.Box, BorderStyle.Single, 0.75);
}
}
.............
}
FillContent() fills the rows from the datatable into the table inside the document:
row1.Cells[j].AddParagraph(dt.Rows[i][j].ToString());
//adds the value of column into the table row
The Default.aspx file contains the code for generating the PDF:
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using System.Diagnostics;
MigraDoc libraries are used for generating PDF documents, and System.Diagnostics for starting a PDF Viewer:
PDFform pdfForm = new PDFform(GetTable(), Server.MapPath("img2.gif"));
// Create a MigraDoc document
Document document = pdfForm.CreateDocument();
document.UseCmykColor = true;
// Create a renderer for PDF that uses Unicode font encoding
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true);
// Set the MigraDoc document
pdfRenderer.Document = document;
// Create the PDF document
pdfRenderer.RenderDocument();
// Save the PDF document...
string filename = "PatientsDetail.pdf";
pdfRenderer.Save(filename);
// ...and start a viewer.
Process.Start(filename);
The PdfForm object is created and using it, a new MigraDoc is generated. PdfDocumentRenderer renders the PDF document and then saves it. Process.Start(filename) starts a PDF viewer to open the PDF file created using MigraDoc.

itext pdf with list of image and text below

Need help to generate a pdf with a list of image and text describing the image under it.
Tried the below, but getting image and text beside each other. Please need help with this. Thanks.
........
PdfPTable table = new PdfPTable(1);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.setSplitRows(true);
table.setWidthPercentage(90f);
Paragraph paragraph = new Paragraph();
for (int counter = 0; counter < empSize; counter++) {
String imgPath = ... ".png");
Image img = Image.getInstance(imgPath);
img.scaleAbsolute(110f, 95f);
Paragraph textParagraph = new Paragraph("Test" + counter));
textParagraph.setLeading(Math.max(img.getScaledHeight(), img.getScaledHeight()));
textParagraph.setAlignment(Element.ALIGN_CENTER);
Phrase imageTextCollectionPhase = new Phrase();
Phrase ph = new Phrase();
ph.add(new Chunk(img, 0, 0, true));
ph.add(textParagraph);
imageTextCollectionPhase.add(ph);
paragraph.add(imageTextCollectionPhase);
}
PdfPCell cell = new PdfPCell(paragraph);
table.addCell(cell);
doc.add(table);
I assume that you want to get a result that looks like this:
In your case, you are adding all the content (all the images and all the text) to a single cell. You should add them to separate cells as is done in the MultipleImagesInTable example:
public void createPdf(String dest) throws IOException, DocumentException {
Image img1 = Image.getInstance(IMG1);
Image img2 = Image.getInstance(IMG2);
Image img3 = Image.getInstance(IMG3);
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
PdfPTable table = new PdfPTable(1);
table.setWidthPercentage(20);
table.addCell(img1);
table.addCell("Brazil");
table.addCell(img2);
table.addCell("Dog");
table.addCell(img3);
table.addCell("Fox");
document.add(table);
document.close();
}
You can easily change this proof of concept so that a loop is used. Just make sure you put the addCell() methods inside the loop instead of outside the loop.
You can also explicitly create a PdfPCell and combine the text and the image in the same cell like this:
PdfPCell cell = new PdfPCell();
cell.addElement(img1);
cell.addElement(new Paragraph("Brazil"));
table.addCell(cell);

Export specific columns of JTable to PDF

I want to print my JTable content into a PDF file,
I managed to do that except that now I want to exclude the second column and print the other ones, any helpful guidlines please?
for (int rows = 0; rows < jTable1.getRowCount(); rows++) {
for (int cols = 0; cols < jTable1.getColumnCount(); cols++) {
PdfPCell cell1 = new PdfPCell(new Phrase(jTable1.getModel().getValueAt(rows,cols).toString(),cellFont));
pdfTable.addCell(cell1);
}
float[] columnWidths = new float[] {10f,1f,13f,35f,15f,25f,20f,15f,13f,
13f,12f,18f,13f,12f,47f,9f,47f};
pdfTable.setWidths(columnWidths);
}
I managed to solve the problem by just putting 0f as the column width of the column that I want to hide !

link coming twice while exporting to pdf using itextsharp

my asp boundfield:
<asp:BoundField DataField = "SiteUrl" HtmlEncode="false" HeaderText = "Team Site URL" SortExpression = "SiteUrl" ></asp:BoundField>
My itextsharpcode
for (int i = 0; i < dtUIExport.Rows.Count; i++)
{
for (int j = 0; j < dtUIExport.Columns.Count; j++)
{
if (j == 1)
{ continue; }
string cellText = Server.HtmlDecode(dtUIExport.Rows[i][j].ToString());
// cellText = Server.HtmlDecode((domainGridview.Rows[i][j].FindControl("link") as HyperLink).NavigateUrl);
// string cellText = Server.HtmlDecode((domainGridview.Rows[i].Cells[j].FindControl("hyperLinkId") as HyperLink).NavigateUrl);
iTextSharp.text.Font font = new iTextSharp.text.Font(bf, 10, iTextSharp.text.Font.NORMAL);
font.Color = new BaseColor(domainGridview.RowStyle.ForeColor);
iTextSharp.text.pdf.PdfPCell cell = new iTextSharp.text.pdf.PdfPCell(new Phrase(12, cellText, font));
pdfTable.AddCell(cell);
}
}
domainGridview is the grid name. However I am manipulating the pdf using data table.
The hyperlink is coming in this way
http://dtsp2010vm:47707/sites/TS1>http://dtsp2010vm:47707/sites/TS1
How to rip the addtional link?
Edit: i have added the screenshot of pdf file
Your initial question didn't get an answer because it is rather misleading. You claim link coming twice, but that's not true. From the point of view, the link is shown as HTML syntax:
http://stackoverflow.com
This is the HTML definition of a single link that is stored in the cellText parameter.
You are adding this content to a PdfPCell as if it were a simple string. It shouldn't surprise you that iText renders this string as-is. It would be a serious bug if iText didn't show:
http://stackoverflow.com
If you want the HTML to be rendered, for instance like this: http://stackoverflow.com, you need to parse the HTML into iText objects (e.g. the <a>-tag will result in a Chunk object with an anchor).
Parsing HTML for use in a PdfPCell is explained in the following question: How to add a rich Textbox (HTML) to a table cell?
When you have http://stackoverflow.com, you are talking about HTML, not just ordinary text. There's a big difference.
I wrote this code for achiveing my result. Thanks Bruno for your answer
for (int j = 0; j < dtUIExport.Columns.Count; j++)
{
if (j == 1)
{ continue; }
if (j == 2)
{
String cellTextLink = Server.HtmlDecode(dtUIExport.Rows[i][j].ToString());
cellTextLink = Regex.Replace(cellTextLink, #"<[^>]*>", String.Empty);
iTextSharp.text.Font fontLink = new iTextSharp.text.Font(bf, 10, iTextSharp.text.Font.NORMAL);
fontLink.Color = new BaseColor(domainGridview.RowStyle.ForeColor);
iTextSharp.text.pdf.PdfPCell cellLink = new iTextSharp.text.pdf.PdfPCell(new Phrase(12, cellTextLink, fontLink));
pdfTable.AddCell(cellLink);
}

iText - add a portion of one PDF to another

I have two PDFs. One is the main PDF and the other has an image that I need to insert into the first. Also in the second PDF, after inserting that image, I need to concatenate the remainder of the second PDF.
The solution was to superimpose the PDF page with the image onto the main PDF. Then concatenate the rest of it. "design_section" is the PDF with the image in it. This code will do:
PdfReader confirmation_section = new PdfReader(SOURCE);
PdfReader design_section = new PdfReader(SOURCE2);
PdfStamper stamper = new PdfStamper(confirmation_section, new FileOutputStream(RESULT));
PdfImportedPage page = stamper.getImportedPage(design_section, 1);
int c = confirmation_section.getNumberOfPages();
PdfContentByte background;
for (int i = 1; i <= c; i++) {
background = stamper.getUnderContent(i);
if(i == c)
background.addTemplate(page, 0, 0);
}
int d = design_section.getNumberOfPages();
if(d > 1) {
for(int f = 2; f <= d; f++) {
stamper.insertPage(c + f, confirmation_section.getPageSize(1));
page = stamper.getImportedPage(design_section, f);
stamper.getOverContent(c + f - 1).addTemplate(page, 0, 0);
System.out.println("here we are in the loop c + f is: " + (c + f));
}
}
stamper.close();
Pointed suggestion for iText -- how about renaming "addTemplate()" to "addPage()"???. iText is the most cryptic lib I have used and that includes regexp
Thanks for the follow up. I did read that many, many times ))) well, honestly, at least 6 times. I know it is just an excerpt and I am sure that there is more valuable information in the book, but with that said, I did not find what I was looking for. Where in that text does it discuss, compare and differentiate PdfCopy PDFStamper and PDFReader/Writer in the context of, for example, adding pages from one PDF to another?