My issue is as this: I want to create a PDF file and in this file there will be a title section which will contain an image and some description, and under it there will be a table contains transactions, the table will have a header that I want to repeat in each page of the PDF as long as there is more transactions. But as I understood there is no way to know that the PDF will start a new page unless something new is added and this new thing will go into the new page.
My code is like this:
public byte[] GeneratePDF(List<Transaction> trasnactions,byte[] imageBinary)
{
byte[] pdfByte = null;
try
{
using (MemoryStream memoryStream = new MemoryStream())
{
Document doc = new Document(PageSize.A4.Rotate());
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);
doc.Open();
PdfPTable headerTable = new PdfPTable(2);
headerTable.DefaultCell.Border = Rectangle.NO_BORDER;
headerTable.DefaultCell.Padding = 0f;
headerTable.WidthPercentage = 100f;
float headerTableFontSize = 10;
headerTable.AddCell(GenerateCell(" ", 2));
headerTable.AddCell(GenerateCell(" ", 2));
headerTable.AddCell(GenerateCell("", 1, 1, headerTableFontSize);
headerTable.AddCell(GenerateImage(imageBinary, 1, 6));
headerTable.AddCell(GenerateCell("Address", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell("", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell("City", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell("12345", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell("Canada", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell(" ", 2));
headerTable.AddCell(GenerateCell(" ", 2));
headerTable.AddCell(GenerateCell("Info", 1, 1, 14, true));
headerTable.AddCell(GenerateCell(""));
headerTable.AddCell(GenerateCell("From 2023-10-10 to 2023-11-10", 1, 1, headerTableFontSize, true));
headerTable.AddCell(GenerateCell(""));
headerTable.AddCell(GenerateCell("User ID: 10", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell(""));
headerTable.AddCell(GenerateCell("Account ID: 10", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell(""));
headerTable.AddCell(GenerateCell("Account Number: 1234****5678", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell(""));
headerTable.AddCell(GenerateCell("Account Currency: CAD", 1, 1, headerTableFontSize));
headerTable.AddCell(GenerateCell(""));
doc.Add(headerTable);
float headerFontSize = 8;
float recordFontSize = 8;
PdfPTable recordTable = PrepareTableWithHeaders(headerFontSize);
recordTable.AddCell(GenerateLine(false, 7, 1, 2));
doc.Add(recordTable);
int pageNumber = writer.PageNumber;
if (trasnactions?.Count > 0)
{
for (int index = 0; index < trasnactions.Count; index++)
{
recordTable = PrepareTableWithHeaders(headerFontSize, false);
recordTable.AddCell(GenerateCell(trasnactions[index].server_date.ToString(), 1, 1, recordFontSize));
recordTable.AddCell(GenerateCell(trasnactions[index].description, 1, 1, recordFontSize));
recordTable.AddCell(GenerateCell(trasnactions[index].currency, 1, 1, recordFontSize));
recordTable.AddCell(GenerateCell(trasnactions[index].amount.ToString(), 1, 1, recordFontSize));
recordTable.AddCell(GenerateCell("0.00", 1, 1, recordFontSize)); //FX Rate
string debitAmount = "0.00";
string creditAmount = "0.00";
if (trasnactions[index].is_credit == 1)
{
creditAmount = trasnactions[index].amount.ToString();
}
else
{
debitAmount = trasnactions[index].amount.ToString();
}
recordTable.AddCell(GenerateCell(debitAmount, 1, 1, recordFontSize));
recordTable.AddCell(GenerateCell(creditAmount, 1, 1, recordFontSize));
recordTable.AddCell(GenerateLine(true, 7, 1, 0));
doc.Add(recordTable);
if (pageNumber != writer.PageNumber)
{
pageNumber = writer.PageNumber;
var headerColumns = PrepareTableWithHeaders(headerFontSize, true);
doc.Add(headerColumns);
}
}
}
doc.Close();
pdfByte = memoryStream.ToArray();
memoryStream.Close();
}
}
catch (Exception ex)
{
throw ex;
}
return pdfByte;
}
private PdfPCell GenerateCell(string input, int colSpan = 1, int rowSpan = 1, float fontSize = 10, bool isBold = false, int horizontalAlignment = Element.ALIGN_LEFT,
BaseColor backgroundColor = null, float padding = 2f, BaseColor fontColor = null)
{
int fontStyle = Font.NORMAL;
if (isBold)
fontStyle = Font.BOLD;
iTextSharp.text.Font font = new Font(FontFactory.GetFont("Arial", fontSize, fontStyle, fontColor));
PdfPCell cell = new PdfPCell(new Phrase(input, font));
cell.Colspan = colSpan;
cell.Rowspan = rowSpan;
cell.Border = Rectangle.NO_BORDER;
cell.HorizontalAlignment = horizontalAlignment;
cell.VerticalAlignment = Element.ALIGN_CENTER;
cell.BackgroundColor = backgroundColor;
cell.Padding = padding;
return cell;
}
private PdfPCell GenerateImage(byte[] imageBinary, int colSpan = 1, int rowSpan = 1)
{
PdfPCell cell;
if (imageBinary != null)
{
Image jpg = Image.GetInstance(imageBinary);
jpg.ScaleToFit(170f, 100f);
cell = new PdfPCell(jpg);
}
else
{
cell = new PdfPCell(new Phrase(" "));
}
cell.Colspan = colSpan;
cell.Rowspan = rowSpan;
cell.Border = Rectangle.NO_BORDER;
cell.HorizontalAlignment = Element.ALIGN_RIGHT;
return cell;
}
private PdfPCell GenerateLine(bool isDottedLine, int colSpan = 1, int rowSpan = 1, float lineWidth = 0.0f)
{
Paragraph paragraph;
BaseColor lineColor = BaseColor.GRAY;
if (lineWidth == 0)
lineColor = BaseColor.BLACK;
if (isDottedLine)
{
var dottedLine = new iTextSharp.text.pdf.draw.DottedLineSeparator();
dottedLine.Gap = 2f;
dottedLine.LineColor = lineColor;
dottedLine.LineWidth = 0.5f;
paragraph = new Paragraph(new Chunk(dottedLine));
}
else
{
paragraph = new Paragraph(new Chunk(new iTextSharp.text.pdf.draw.LineSeparator(lineWidth, 100.0F, lineColor, Element.ALIGN_LEFT, 1)));
}
PdfPCell cell = new PdfPCell(paragraph);
cell.Colspan = colSpan;
cell.Rowspan = rowSpan;
cell.Border = Rectangle.NO_BORDER;
cell.PaddingTop = -6f;
cell.VerticalAlignment = Element.ALIGN_CENTER;
return cell;
}
private PdfPTable PrepareTableWithHeaders(float headerFontSize, bool isAddHeaders = true)
{
PdfPTable recordTable = new PdfPTable(7);
float[] widths1 = new float[] { 10f, 30f, 10f, 10f, 10f, 10f, 10f };
recordTable.SetWidths(widths1);
recordTable.WidthPercentage = 100f;
recordTable.DefaultCell.Padding = 0f;
if (isAddHeaders)
{
recordTable.AddCell(GenerateCell("Date", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Transaction", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Currency", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Amount", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Rate", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Debits", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateCell("Credits", 1, 1, headerFontSize, true, 0, null, 0));
recordTable.AddCell(GenerateLine(false, 7));
}
return recordTable;
}
What I tried is to have a temproray MemoryStream, PDFWriter and Document that I will add to it first and if the page number didn't increase I would add to the main doc if not I would create a new page in the main doc, add the header table to it and copy the main doc to the temp doc and continue, somehting like this:
if (pageNumber != tempWriter.PageNumber)
{
pageNumber = tempWriter.PageNumber;
var headerColumns = PrepareTableWithHeaders(headerFontSize, account.Currency, true);
doc.NewPage();
doc.Add(headerColumns);
doc.Add(recordTable);
tempDoc = doc.Copy();
tempWriter = PdfWriter.GetInstance(tempDoc, tempMemStream);
tempDoc.Open();
}
else
{
doc.Add(recordTable);
}
but this broke the temp doc and made it have some kind of a static pagenumber never to be increased. can this be done like this in the first place? or there is a better way to do this?