iText7: Adding a PDF inside a Cell (cutoff at end of page) - c#

We are creating a PDF, it contains a large table, with headers (bold), sub-headers (non bold), rows and cells.
One of the requirements is to add an already existing PDF (can be multiple pages) inside the cell (under the sub-header). And this is where we are struggling. What we have tried so far:
Converting the PDF to a FormXObject, and adding that into the cell.
FontProvider fontProvider = new FontProvider();
ConverterProperties props = new ConverterProperties();
props.SetFontProvider(fontProvider);
var historyId = text.Replace("=Spectec_template", "");
var pdfTemplate = templateToPdfClient.GetPdf(historyId, "HI").Result;
PdfDocument srcDoc = new PdfDocument(new PdfReader(pdfTemplate.FileStream));
for (int i = 1; i < srcDoc.GetNumberOfPages() + 1; i++)
{
Cell newCell = new Cell(1, columnInfo.ColumnSpan).SetFont(PdfFontFactory.CreateFont(_fontName));
PdfPage origPage = srcDoc.GetPage(i);
Rectangle rect = origPage.GetPageSize();
PdfFormXObject pageCopy = origPage.CopyAsFormXObject(pdf);
Image image = new Image(pageCopy);
image.SetBorder(Border.NO_BORDER);
image.SetMaxWidth(UnitValue.CreatePercentValue(100));
image.SetMaxHeight(UnitValue.CreatePercentValue(50));
Div div = new Div();
div.Add(image.SetMaxWidth(UnitValue.CreatePercentValue(100)));
newCell.Add(div);
newCell = ApplyLayoutsToCell(newCell, cellStyles);
table.AddCell(newCell);
}
But the end result is that we only see 1 page and it's completely overlapping at the end of the page.
When we set image.SetAutoScale(true); the PDF is visible but it's extremely small.
When adding the Image to a Paragraph instead of a DIV the PDF pages display next to each other.
Any ideas, suggestions?
Thank you

Thanks to #mkl and #KJ I figured this out.
I ended up adding each PDF page in a new Cell, and setting the scaling of image to 0.6f.
for (int i = 1; i < srcDoc.GetNumberOfPages() + 1; i++)
{
newCell = new Cell(1, columnInfo.ColumnSpan).SetFont(PdfFontFactory.CreateFont(_fontName));
PdfPage origPage = srcDoc.GetPage(i);
PdfFormXObject pageCopy = origPage.CopyAsFormXObject(pdf);
Image image = new Image(pageCopy);
image.SetBorder(Border.NO_BORDER);
image.Scale(0.6f, 0.6f);
newCell.Add(image);
newCell = ApplyLayoutsToCell(newCell, cellStyles);
table.AddCell(newCell);
}

Related

addind text with itext7

I want to add text into every page of my pdf which is rotaded from bottom to top.
Like this:
Here is my code:
PdfDocument srcDocument = new PdfDocument(new PdfReader(file));
PdfDocument destDocument = new PdfDocument(new PdfWriter(newfile));
int pagesCount = srcDocument.GetNumberOfPages();
for (int i = 1; i <= pagesCount; i++)
{
srcDocument.CopyPagesTo(i, i, destDocument);
PdfCanvas pdfCanvas = new PdfCanvas(srcDocument.GetPage(i));
}
srcDocument.Close();
destDocument.Close();
In this I got stuck. I don't know how to go further : write and rotate text.
So, as per the comments on the original question, you basically need to print on a Canvas object, and rotate the Paragraph. The Rectangle basically defines the coordinates where you will place the Canvas. Something like this should work:
PdfDocument srcDocument = new PdfDocument(new PdfReader(file));
PdfDocument destDocument = new PdfDocument(new PdfWriter(newfile));
FontProgram fontProgram =
FontProgramFactory.CreateFont(#"C:\temp\calibri.ttf");
PdfFont calibri = PdfFontFactory.CreateFont(fontProgram, PdfEncodings.WINANSI);
int pagesCount = srcDocument.GetNumberOfPages();
for (int i = 1; i <= pagesCount; i++)
{
srcDocument.CopyPagesTo(i, i, destDocument);
PdfCanvas pdfCanvas = new PdfCanvas(destDocument.GetPage(i));
Canvas canvas = new Canvas(pdfCanvas, new Rectangle(36, 750, 100, 50));
canvas.Add(new Paragraph("0001").SetRotationAngle(1.5708).SetFont(calibri).SetFontSize(4));
canvas.Close();
}
srcDocument.Close();
destDocument.Close();
Alternatively, you can set a Style, if you plan on reusing a lot, something like:
Style rotatedStuff = new Style()
.SetRotationAngle(1.5708)
.SetFont(calibri)
.SetFontSize(4);
and then just apply it to the Paragraph with the AddStyle() method.
Mind you that if you provide with a float number, it's in rads, so 90° is 1.5708 rad (1 Degree (°) = 0.01745 Radian (rad)).

Add footer to every page of an existing PDF in iText7 (.NET)

I am building a PDF at runtime in itext7.pdfHTML, using a template file. I want to add a footer to every page of the resulting PDF, which has two pages, but for some reason the footer only appears on the second page.
I'm trying to build on this example from the iText website. The example deals with page numbers, but since I'm just adding static text to my document, the principle is the same. Here's my code:
string footer = "This is the footer".
string body = "<span>This is raw HTML</span>";
//create a temporary PDF with the raw HTML, made from my template and given data
private void createPDF()
{
destination = System.IO.Path.Combine(HttpContext.Current.Server.MapPath("~/pdf_repo"), "tempFile.pdf");
ConverterProperties properties = new ConverterProperties();
properties.SetBaseUri(HttpContext.Current.Server.MapPath("~/templates/"));
HtmlConverter.ConvertToPdf(body, new FileStream(destination, FileMode.Create), properties);
addFooter(id);
}
//modify the PDF file created above by adding the footer
private void addFooter(string id)
{
string newFile = System.IO.Path.Combine(HttpContext.Current.Server.MapPath("pdf_repo", "finalFile.pdf");
PdfDocument pdfDoc = new PdfDocument(new PdfReader(destination), new PdfWriter(newFile));
Document doc = new Document(pdfDoc);
Paragraph foot = new Paragraph(footer);
foot.SetFontSize(8);
float x = 300; //559
float y = 0; //806
int numberOfPages = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= numberOfPages; i++)
{
doc.ShowTextAligned(foot, x, y, TextAlignment.CENTER, VerticalAlignment.BOTTOM);
}
doc.Close();
//delete temporary PDF
File.Delete(destination);
}
I've tried setting i to 0 in the addFooter() "for" loop, but that doesn't solve the issue. How can I get the footer to appear on every page?
Yeah, you weren't specifying which page to add the footer to, so it only added it to the bottom of the entire document. Try this:
Note, the only change was: doc.ShowTextAligned(foot, x, y, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM);
string footer = "This is the footer".
string body = "<span>This is raw HTML</span>";
//create a temporary PDF with the raw HTML, made from my template and given data
private void createPDF()
{
destination = System.IO.Path.Combine(HttpContext.Current.Server.MapPath("~/pdf_repo"), "tempFile.pdf");
ConverterProperties properties = new ConverterProperties();
properties.SetBaseUri(HttpContext.Current.Server.MapPath("~/templates/"));
HtmlConverter.ConvertToPdf(body, new FileStream(destination, FileMode.Create), properties);
addFooter(id);
}
//modify the PDF file created above by adding the footer
private void addFooter(string id)
{
string newFile = System.IO.Path.Combine(HttpContext.Current.Server.MapPath("pdf_repo", "finalFile.pdf");
PdfDocument pdfDoc = new PdfDocument(new PdfReader(destination), new PdfWriter(newFile));
Document doc = new Document(pdfDoc);
Paragraph foot = new Paragraph(footer);
foot.SetFontSize(8);
float x = 300; //559
float y = 0; //806
int numberOfPages = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= numberOfPages; i++)
{
doc.ShowTextAligned(foot, x, y, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM);
}
doc.Close();
//delete temporary PDF
File.Delete(destination);
}

How to get a long table drawed starting from the top of page using iText7 in C#?

PDF Page Example
The PDF is composed by serveral paragraphs added to the document, and there is a long table which need to set started from top of one page(not the first page) which means a paragraph will be splitted to two parts.
If the table is short(length not exceed the page height), it can be done gracefully by handling Page Event of start page, just added the table to the canvas with the fixed position and size, and set the document's top margin.
PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
PdfDocument pdfDoc = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
var currentPageNumber = pdfDoc.GetPageNumber(page);
var addingTablesOfPage = addingTables.Where(t => t.PageNumber == currentPageNumber && t.Prepared).ToList();
if (addingTablesOfPage != null && addingTablesOfPage.Count > 0)
{
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
PageSize pageSize = pdfDoc.GetDefaultPageSize();
var pageHeight = pageSize.GetHeight() - Constants.DocumentMargins[0] - Constants.DocumentMargins[2];
var pageWidth = pageSize.GetWidth() - Constants.DocumentMargins[1] - Constants.DocumentMargins[3];
var totalHeight = 0f;
var alignRight = false;
// add tables to the top of page
foreach (var table in addingTablesOfPage.OrderBy(t => t.Type).ToList())
{
var tableWidth = 0f;
float coordX = 0;
tableWidth = pageWidth;
coordX = pageSize.GetX() + doc.GetLeftMargin();
totalHeight += table.TableHeight;
float coordY = pageSize.GetTop() - Constants.DocumentMargins[0] - totalHeight;
Rectangle rect = new Rectangle(coordX, coordY, tableWidth, table.TableHeight);
var tableCanvas = new Canvas(canvas, rect);
tableCanvas.Add(table.Table);
tableCanvas.Close();
}
float topMargin = Constants.DocumentMargins[0] + totalHeight;
doc.SetTopMargin(topMargin);
}
else
{
doc.SetTopMargin(Constants.DocumentMargins[0]);
}
But here the table is too long which will be splitted to multi pages. As far as I known, Canvas class is primarily aimed at cases when you need to add elements to a specific predefined area on a page / XObject and it is not aimed at overflowing your content to next areas. So how can I achieve the behavior?
Thank you!
The description of what you are trying to achieve is quite vague (not clear if it's paragraph wrapping around table, or if it's a table in between paragraph; not clear if the table is bound to any text in paragraph or not etc etc), but my answer should guide you to the right direction.
I will show you how to add the paragraph part that fits till the end of the current page to the document, then add your table spanning across more than one page, and then add the leftover part of your paragraph.
First off, we need a custom renderer for our paragraph that will only render the part that currently fits in the page and will remember the rest to be added later.
private static class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer leftover;
private CustomParagraphRenderer toDraw;
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
if (result.getStatus() == LayoutResult.PARTIAL) {
// Expected result here is that paragraph splits across pages
leftover = (CustomParagraphRenderer) result.getOverflowRenderer();
toDraw = (CustomParagraphRenderer) result.getSplitRenderer();
return new LayoutResult(LayoutResult.FULL, result.getSplitRenderer().getOccupiedArea(), null, null);
}
return result;
}
#Override
public void draw(DrawContext drawContext) {
if (toDraw != null) {
toDraw.draw(drawContext);
} else {
super.draw(drawContext);
}
}
#Override
public IRenderer getNextRenderer() {
return new CustomParagraphRenderer((Paragraph) modelElement);
}
}
Now, we are adding some placeholder rectangle to the document just to occupy some space for the testing purposes, then we add our paragraph with our custom renderer (note that the expectation is that the paragraph will be rendered as much as possible on the current page, and the leftover part will be remembered), then we add our table spanning across multiple pages, and finally, we add our leftover paragraph part.
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Document document = new Document(pdfDocument);
document.setFontSize(20);
Div emptyArea = new Div().setHeight(400).setBackgroundColor(ColorConstants.RED);
document.add(emptyArea);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i++) {
sb.append(i).append(" ");
}
Paragraph p = new Paragraph(sb.toString());
p.setNextRenderer(new CustomParagraphRenderer(p).setParent(document.getRenderer()));
CustomParagraphRenderer paragraphRenderer = (CustomParagraphRenderer) p.createRendererSubTree();
// Add first part of the paragraph
document.getRenderer().addChild(paragraphRenderer);
Table table = new Table(3);
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 3; j++) {
table.addCell(new Cell().add(new Paragraph("Cell (" + i + ", " + j + ")")));
}
}
// Add big table
document.add(table);
// Add leftover paragraph part
document.getRenderer().addChild(paragraphRenderer.leftover.setParent(document.getRenderer()));
document.close();
Result looks as follows. Note that I deliberately added consequent numbers as paragraph content so that it's clear that it's a continuous paragraph that is interrupted with a table:

Adding text as watermark using itext7 C#

I am using the below code to add watermark to my pdf.
private void Merge(List<string> src, string dest)
{
iTextKernel.PdfWriter writer = new iTextKernel.PdfWriter(dest);
iTextKernel.PdfDocument pdfDocument1 = new iTextKernel.PdfDocument(new iTextKernel.PdfReader(src[0]), writer);
pdfDocument1.AddEventHandler(PdfDocumentEvent.END_PAGE, new WatermarkingEventHandler());
for (int i = 1, max = src.Count; i < max; i++)
{
iTextKernel.PdfDocument pdfDocument2 = new iTextKernel.PdfDocument(new iTextKernel.PdfReader(src[i]));
var pagesCount = pdfDocument2.GetNumberOfPages();
pdfDocument2.CopyPagesTo(1, pagesCount, pdfDocument1);
pdfDocument2.Close();
}
pdfDocument1.Close();
protected class WatermarkingEventHandler : IEventHandler {
public void HandleEvent(Event e) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) e;
iTextKernel.PdfDocument pdfDoc = docEvent.GetDocument();
iTextKernel.PdfPage page = docEvent.GetPage();
iText.Kernel.Font.PdfFont font = null;
try {
font = PdfFontFactory.CreateFont(FontConstants.HELVETICA_BOLD);
} catch (IOException ex) {
//_log.Error(ex);
}
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
new Canvas(canvas, pdfDoc, page.GetPageSize())
.SetFontColor(iText.Kernel.Colors.DeviceGray.LIGHT_GRAY)
.SetFontSize(60)
.SetFont(font)
.ShowTextAligned(new Paragraph("FOR YOUR RECORDS ONLY: DO NOT SUBMIT"), 298, 421, pdfDoc.GetPageNumber(page),
TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
}
But am getting the watermark only in the last page that too hidden under the contents. Could you please modify this code so that i could get the watermark on all the pages and shown over the contents.
Please take a look at the iText 7 for C# jump-start tutorial, more specifically Chapter 5: Manipulating an existing PDF document. Scroll to the part where it says: "Adding a header, footer, and watermark" and look at the example:
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
Document document = new Document(pdfDoc);
Rectangle pageSize;
PdfCanvas canvas;
int n = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdfDoc.GetPage(i);
pageSize = page.GetPageSize();
canvas = new PdfCanvas(page);
//Draw header text
}
pdfDoc.close();
As you can see, we only need one PdfDocument instance, but instead of passing only a PdfWriter, we also pass a PdfReader instance. We will read the file with path src and we will write to a file with path dest.
You want to add content to each page. This means that you have to loop over each page (from 1 to n). Get the PdfPage object for each page i and replace the line //Draw header text with whatever it is you want to do.
In your case, you add an image underneath the existing content. That is the normal thing to do, but you say that the watermark is covered by the existing content. That happens for instance when the actual content consists of images (e.g. scanned pages). If you add a watermark under the pages of a PDF that consists of scanned pages, you will never see the watermark.
In that case, you have to add the content on top of the existing content, but it is best to make the watermark transparent:
Paragraph p = new Paragraph("FOR YOUR RECORDS ONLY: DO NOT SUBMIT").SetFontSize(60);
canvas.SaveState();
PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.2f);
canvas.SetExtGState(gs1);
document.ShowTextAligned(p, pageSize.GetWidth() / 2, pageSize.GetHeight() / 2, pdfDoc.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
canvas.RestoreState();
Note that in the tutorial, we are using pageSize.GetWidth() / 2 and pageSize.GetHeight() / 2 as coordinates, which means that we assume that the lower-left corner of the page has the coordinate (0, 0). That may not be the case. You may have to add the x-offset and the y-offset to that value.

iTextSharp - dynamic content with a footer, using padding

I am attempting to create documents that are highly-variable in length, and make them something that can be table-driven. I am trying to use iTextSharp tables exclusively to create the documents, including footer verbiage. In the code below I’m trying to pad the very last cell to the exact amount equal to the remaining space, so that my footer will be placed exactly at the bottom of the document, tight against the bottom margin. This works fine when I try to use document margins of 1, 2, or 3 inches, but when I use 5 for example, my footer begins to wrap. I think this may simply be a case of bad math. Does anyone have any suggestions to correct this (outside of using Page Events)?
(*Note: there are 2 helper methods used in creating tables and measuring the height of a paragraph, also included in addition to the main code from a button click)
(*Note: each table has SplitLate set to false, to make the content flow from page to page evenly); all tables have a specific width, and the width is locked
//declare path for the PDF file to be created
string strpath = #"C:\CROauto\Junk\MSE.pdf";
//instantiate a new PDF document
//(regular portrait format, with half-inch margins all around)
var doc = new Document(PageSize.LETTER,
iTextSharp.text.Utilities.InchesToPoints(1f),
iTextSharp.text.Utilities.InchesToPoints(1f),
iTextSharp.text.Utilities.InchesToPoints(5f),
iTextSharp.text.Utilities.InchesToPoints(.5f));
//create a PDF table
//(2 column, with no border)
PdfPTable mas_tbl = clsPDF.CreateTable(2, false, cell_padding_bottom: 0f, total_width: doc.PageSize.Width - doc.LeftMargin - doc.RightMargin);
//get base font types
BaseFont font_tb = FontFactory.GetFont(FontFactory.TIMES_BOLD).BaseFont;
BaseFont font_t = FontFactory.GetFont(FontFactory.TIMES).BaseFont;
//create regular Font objects, with varying sizes
iTextSharp.text.Font f10 = new iTextSharp.text.Font(font_t, 10);
iTextSharp.text.Font f8 = new iTextSharp.text.Font(font_t, 8);
//create regular Font objects, bold, with varying sizes
iTextSharp.text.Font fb10 = new iTextSharp.text.Font(font_tb, 10);
iTextSharp.text.Font fb8 = new iTextSharp.text.Font(font_tb, 8);
//get image
iTextSharp.text.Image da_img = iTextSharp.text.Image.GetInstance(#"C:\CROauto\Junk\img.gif");
//scale the image to a good size
da_img.ScaleAbsolute(iTextSharp.text.Utilities.InchesToPoints(.75f),
iTextSharp.text.Utilities.InchesToPoints(.75f));
//create new PDF cell to hold image
PdfPCell icell = new PdfPCell();
icell.PaddingBottom = 0f;
//make sure the "image" cell has no border
icell.Border = iTextSharp.text.Rectangle.NO_BORDER;
//add the image to the PDF cell
icell.AddElement(da_img);
//add the image cell to the table
mas_tbl.AddCell(icell);
//work with the return address
PdfPCell ra = new PdfPCell();
ra.Border = iTextSharp.text.Rectangle.NO_BORDER;
ra.PaddingBottom = 5f;
PdfPTable tblra = clsPDF.CreateTable(1, false);
tblra.HorizontalAlignment = Element.ALIGN_RIGHT;
Chunk c = new Chunk("Help Me Please", fb8);
string rtnadd = "\r\n123 iTextSharp Rd\r\nHelpMe, ST 12345\r\n\r\nstackoverflow.com";
Phrase pra = new Phrase(rtnadd, f8);
Paragraph p = new Paragraph();
p.SetLeading(1f, 1.1f);
p.Add(c);
p.Add(pra);
tblra.TotalWidth = clsPDF.GetLongestWidth(p) + ra.PaddingLeft + ra.PaddingRight + 2;
ra.AddElement(p);
tblra.AddCell(ra);
PdfPCell dummy = new PdfPCell();
dummy.PaddingBottom = 0f;
dummy.Border = iTextSharp.text.Rectangle.NO_BORDER;
dummy.AddElement(tblra);
mas_tbl.AddCell(dummy);
//create "content" table
PdfPTable t2 = clsPDF.CreateTable(1, false, Element.ALIGN_JUSTIFIED, cell_padding_bottom: 0f);
//create FileStream for the file
using (FileStream fs = new FileStream(strpath, FileMode.Create))
{
//get an instance of a PdfWriter, attached to the FileStream
PdfWriter.GetInstance(doc, fs);
//open the document
doc.Open();
string tmp = "";
for (int i = 0; i < 80; i++)
{
tmp += "The brown fox jumped over the lazy dog a whole bunch of times." + i.ToString();
}
Phrase p2 = new Phrase(tmp, f10);
t2.AddCell(p2);
p2 = new Phrase("Another paragraph", f10);
t2.AddCell(p2);
tmp = "";
PdfPTable t3 = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
for (int i = 0; i < 150; i++)
{
tmp += "The lazy dog didn't like that very much." + i.ToString();
}
t3.AddCell(new Phrase(tmp, f10));
t2.AddCell(t3);
t2.AddCell(new Phrase("I SURE HOPE THIS WORKED", f10));
PdfPCell c2 = new PdfPCell();
c2.PaddingBottom = 0f;
c2.Border = iTextSharp.text.Rectangle.NO_BORDER;
c2.Colspan = mas_tbl.NumberOfColumns;
c2.AddElement(t2);
mas_tbl.AddCell(c2);
//work with adding a footer
//FOOTER MSE: ADD ENOUGH PADDING TO PUSH THE FOOTER TO THE BOTTOM OF THE PAGE
Paragraph fp = new Paragraph(new Phrase("Line 1 of footer\r\nLine 2 of footer\r\nhere's more of my footer text:\r\nthis project was SOOOO much fun\r\nand stuff", fb8));
//get the height of the footer
float footer_height = clsPDF.GetTotalHeightOfParagraph(fp);
Console.WriteLine("Footer height {0}", footer_height.ToString());
//get the total amount of "writeable" space per page
//(taking top and bottom margins into consideration)
float avail = doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin);
//declare a variable to assist in calculating
//the total amount of "writeable" room remaining
//on the last page;
//start with with the current height of the master table
//(will do math below to calculate just what it's using
// on the last page)
float mas_tbl_last_page_height = mas_tbl.TotalHeight;
//the purpose of this loop is to start determining
//how much writeable space is left on the last page;
//this loop will subtract the "available" value from
//the total height of the master table until what's
//left is the amount of space the master table is
//using on the last page of the document only
while (mas_tbl_last_page_height > avail)
{
mas_tbl_last_page_height -= avail;
}
//to truly calculate the amount of writeable space
//remaining, subtract the amount of space that the
//master table is utilizing on the last page of
//the document, from the total amount of writeable
//space per page
float room_remaining = avail - mas_tbl_last_page_height;
//declare variable for the padding amount
//that will be used above the footer
float pad_amt = 0f;
if (room_remaining > (footer_height * 2))
{
//pad to push down
pad_amt = room_remaining - (footer_height * 2);
}
else
{
//don't use a pad
//(just let the table wrap normally)
pad_amt = 0f;
}
//declare the footer cell, and set all of it's values
PdfPCell ftcell = new PdfPCell();
ftcell.HorizontalAlignment = Element.ALIGN_JUSTIFIED;
//(use column span that is equal to the number of
// columns in the master table)
ftcell.Colspan = mas_tbl.NumberOfColumns;
ftcell.Border = iTextSharp.text.Rectangle.NO_BORDER;
ftcell.PaddingTop = pad_amt;
ftcell.PaddingBottom = 0f;
ftcell.AddElement(fp);
//add the footer cell to the master table
mas_tbl.AddCell(ftcell);
//add the master table to the document, which should contain everything
doc.Add(mas_tbl);
//close the document
doc.Close();
//HELPER METHODS
internal static PdfPTable CreateTable(int column_count,
bool include_border,
int h_align = Element.ALIGN_LEFT,
int v_align = Element.ALIGN_TOP,
float leading_multiplier = 1.1f,
float total_width = 468f,
float cell_padding_bottom = 5f,
float cell_padding_top = 0)
{
////////////////////////////////////////////////////////////////////////////////////
PdfPTable t = new PdfPTable(column_count);
//this line will keep the inner tables,
//from splitting off onto a 2nd page
//(making them only do it on wrapping)
//*NOTE: this needs to be tested thoroughly
// to make sure that rows aren't dropped!!!
t.SplitLate = false;
//used if you're adding paragraphs directly to table cells,
//instead of adding new PdfPCell objects
if (include_border == false)
{
t.DefaultCell.Border = Rectangle.NO_BORDER;
}
t.DefaultCell.PaddingLeft = 0f;
t.DefaultCell.PaddingRight = 0f;
t.DefaultCell.PaddingTop = cell_padding_top;
t.DefaultCell.PaddingBottom = cell_padding_bottom;
t.DefaultCell.HorizontalAlignment = h_align;
t.DefaultCell.VerticalAlignment = h_align;
t.TotalWidth = total_width;
t.LockedWidth = true;
t.DefaultCell.SetLeading(0, leading_multiplier);
return t;
}
internal static float GetLongestWidth(Paragraph p)
{
List<float> f = new List<float>();
foreach (Chunk c in p.Chunks)
{
string[] strarray = c.Content.Split(new string[] { "\r\n" }, System.StringSplitOptions.None);
for (int i = 0; i < strarray.Length; i++)
{
Chunk tc = new Chunk(strarray[i], c.Font);
Console.WriteLine(tc.Content + ", width: {0}", tc.GetWidthPoint().ToString());
f.Add(tc.GetWidthPoint());
}
}
return f.Max();
}
internal static float GetTotalHeightOfParagraph(Paragraph p)
{
PdfPTable t = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
t.DefaultCell.PaddingBottom = 0f;
t.DefaultCell.PaddingTop = 0f;
t.AddCell(p);
return t.TotalHeight;
}
Solved it by using absolute positioning. I calculate the position that the footer should be in, by adding the footer height to the value of the bottom margin. To alleviate concerns about overwriting existing content, I calculate the amount of available space remaining on the last page; if it's not enough for my footer, I add a new page and post my content at the beginning of the next page.
byte[] content;
using (MemoryStream output = new MemoryStream())
{
PdfReader pdf_rdr = new PdfReader(strpath);
PdfStamper stamper = new PdfStamper(pdf_rdr, output);
PdfContentByte pcb = stamper.GetOverContent(pdf_rdr.NumberOfPages);
PdfPTable ftbl = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
Paragraph fp = new Paragraph(new Phrase("Line 1 of footer\r\nLine 2 of footer\r\nhere's more of my footer text:\r\nthis project was SOOOO much fun\r\nand stuff", fb8));
//get the height of the footer
float footer_height = clsPDF.GetTotalHeightOfParagraph(fp);
Console.WriteLine("Footer height {0}", footer_height.ToString());
//get the total amount of "writeable" space per page
//(taking top and bottom margins into consideration)
float avail = doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin);
//declare a variable to assist in calculating
//the total amount of "writeable" room remaining
//on the last page;
//start with with the current height of the master table
//(will do math below to calculate just what it's using
// on the last page)
float mas_tbl_last_page_height = mas_tbl.TotalHeight;
mas_tbl_last_page_height = mas_tbl_last_page_height % avail;
avail = avail - mas_tbl_last_page_height;
Console.WriteLine(clsPDF.GetTotalHeightOfParagraph(fp).ToString());
//float ft_top = avail - mas_tbl_last_page_height - clsPDF.GetTotalHeightOfParagraph(fp) - doc.BottomMargin;
float ft_top = doc.BottomMargin + clsPDF.GetTotalHeightOfParagraph(fp);
ftbl.AddCell(fp);
if (avail < clsPDF.GetTotalHeightOfParagraph(fp))
{
stamper.InsertPage(pdf_rdr.NumberOfPages + 1, pdf_rdr.GetPageSize(1));
pcb = stamper.GetOverContent(pdf_rdr.NumberOfPages);
ft_top = doc.PageSize.Height - doc.TopMargin;
}
ftbl.WriteSelectedRows(0, -1, doc.LeftMargin, ft_top, pcb);
// Set the flattening flag to true, as the editing is done
stamper.FormFlattening = true;
// close the pdf stamper
stamper.Close();
//close the PDF reader
pdf_rdr.Close();
content = output.ToArray();
}
//write the content to a PDF file
using (FileStream fs = File.Create(strpath))
{
fs.Write(content, 0, (int)content.Length);
fs.Flush();
}

Categories

Resources