After creating a PDF from HTML, I need to add a Footer to each page. The Footer is going to be a single-row, three-column table, with the left cell being an external reference ID, the center being a "Page X of Y", and the right being a date stamp. I have no experience with iTextSharp, but after reading various posts I created the following PageEventHandler
UPDATED CODE
public class FooterEvent : PdfPageEventHelper
{
PdfContentByte cb;
#region Properties
private string _FooterLeft;
public string FooterLeft
{
get { return _FooterLeft; }
set { _FooterLeft = value; }
}
private string _FooterCenter;
public string FooterCenter
{
get { return _FooterCenter; }
set { _FooterCenter = value; }
}
private string _FooterRight;
public string FooterRight
{
get { return _FooterRight; }
set { _FooterRight = value; }
}
private Font _FooterFont;
public Font FooterFont
{
get { return _FooterFont; }
set { _FooterFont = value; }
}
#endregion
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
Font font = new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL, BaseColor.BLACK);
PdfPTable FooterTable = new PdfPTable(3);
FooterTable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin;
PdfPCell FooterLeftCell = new PdfPCell(new Phrase(2, FooterLeft, FooterFont));
FooterLeftCell.HorizontalAlignment = Element.ALIGN_LEFT;
FooterLeftCell.VerticalAlignment = Element.ALIGN_CENTER;
FooterLeftCell.Border = 0;
FooterTable.AddCell(FooterLeftCell);
PdfPCell FooterCenterCell = new PdfPCell(new Phrase(2, FooterCenter, FooterFont));
FooterCenterCell.HorizontalAlignment = Element.ALIGN_CENTER;
FooterCenterCell.VerticalAlignment = Element.ALIGN_CENTER;
FooterCenterCell.Border = 0;
FooterTable.AddCell(FooterCenterCell);
PdfPCell FooterRightCell = new PdfPCell(new Phrase(2, FooterRight, FooterFont));
FooterRightCell.HorizontalAlignment = Element.ALIGN_RIGHT;
FooterRightCell.VerticalAlignment = Element.ALIGN_CENTER;
FooterRightCell.Border = 0;
FooterTable.AddCell(FooterRightCell);
FooterTable.WriteSelectedRows(0, -1, document.LeftMargin, document.BottomMargin, cb);
}
}
ADDED RESPONSE
After editing my PageEvent, I'm still having issues. It's come to mind that I'm probably having issues with calling the PageEvent and adding it to the PDF (no experience with iTextSharp). Below is my attempt to add the Footer to an existing PDF that has been passed as byte[].
byte[] output = null;
string identifier = id;
string time = DateTime.Now.ToString();
string page = null;
PdfReader reader = new PdfReader(original);
int n = reader.NumberOfPages;
try
{
using (MemoryStream ms = new MemoryStream())
{
using (Document doc = new Document(PageSize.LETTER, 100, 100, 100, 100))
{
using (PdfWriter writer = PdfWriter.GetInstance(doc, ms))
{
FooterEvent footer = new FooterEvent();
writer.PageEvent = footer;
footer.FooterFont = FontFactory.GetFont(BaseFont.HELVETICA, 12, BaseColor.BLACK);
doc.Open();
for (int i = 1; i < n + 1; ++i)
{
doc.NewPage();
page = "Page " + i + " of " + n;
footer.FooterLeft = identifier;
footer.FooterCenter = page;
footer.FooterRight = time;
doc.Add(new Paragraph(reader.GetPageContent(i).ToString()));
//Probably wrong. Trying to add contents from each page in original PDF
}
doc.Close();
}
}
output = ms.ToArray();
}
}
catch (Exception ex)
{
//Some Message added later
}
return output;
Any help is appreciated. Thanks in advance.
Try this, its working for me:
FooterTable.WriteSelectedRows(0, -1, document.LeftMargin, FooterTable.TotalHeight, cb);
Check this post
Header, footer and large tables with iTextSharp
You wrote:
FooterTable.WriteSelectedRows(0, 0, document.LeftMargin, document.RightMargin, cb);
However, the method is:
FooterTable.WriteSelectedRows(rowStart, rowEnd, x, y, cb);
Which means that you're asking to write a selection of rows starting with row 0 and ending with row 0, or: you're asking to write not a single row.
Moreover, you provide an x value instead of a y value. Change that line into:
FooterTable.WriteSelectedRows(0, -1, document.LeftMargin, document.BottomMargin, cb);
Related
I'm trying to add a table to the PDF file I'm generating. I can add stuff "directly" but want to put the various paragraphs or phrases in table cells to get everything to align nicely.
The following code should add three paragraphs "free-form" first, then the same three in a table. However, only the first three display - the table is nowhere to be seen. Here's the code:
try
{
using (var ms = new MemoryStream())
{
using (var doc = new Document(PageSize.A4, 50, 50, 25, 25))
{
using (var writer = PdfWriter.GetInstance(doc, ms))
{
doc.Open();
var titleFont = FontFactory.GetFont(FontFactory.COURIER_BOLD, 11, BaseColor.BLACK);
var docTitle = new Paragraph("UCSC Direct - Direct Payment Form", titleFont);
doc.Add(docTitle);
var subtitleFont = FontFactory.GetFont("Times Roman", 9, BaseColor.BLACK);
var subTitle = new Paragraph("(not to be used for reimbursement of services)", subtitleFont);
doc.Add(subTitle);
var importantNoticeFont = FontFactory.GetFont("Courier", 9, BaseColor.RED);
var importantNotice = new Paragraph("Important: Form must be filled out in Adobe Reader or Acrobat Professional 8.1 or above. To save completed forms, Acrobat Professional is required. For technical and accessibility assistance, contact the Campus Controller's Office.", importantNoticeFont);
importantNotice.Leading = 0;
importantNotice.MultipliedLeading = 0.9F; // reduce the width between lines in the paragraph with these two settings
importantNotice.ExtraParagraphSpace = 4; // ? test this....
doc.Add(importantNotice);
// Add a table
PdfPTable table = new PdfPTable(10); // the arg is the number of columns
// Row 1
PdfPCell cell = new PdfPCell(docTitle);
cell.Colspan = 3;
cell.BorderWidth = 0;
//cell.BorderColor = BaseColor.WHITE; <= this works for me, but if background is something other than white, it wouldn't
cell.HorizontalAlignment = 0; //0=Left, 1=Centre, 2=Right
table.AddCell(cell);
// Row 2
PdfPCell cellCaveat = new PdfPCell(subTitle);
cellCaveat.Colspan = 2;
cellCaveat.BorderWidth = 0;
table.AddCell(cellCaveat);
// Row 3
PdfPCell cellImportantNote = new PdfPCell(importantNotice);
cellImportantNote.Colspan = 5;
cellImportantNote.BorderWidth = 0;
table.AddCell(importantNotice);
doc.Add(table);
doc.Close();
}
var bytes = ms.ToArray();
String PDFTestOutputFileName = String.Format("iTextSharp_{0}.pdf", DateTime.Now.ToShortTimeString());
PDFTestOutputFileName = PDFTestOutputFileName.Replace(":", "_");
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), PDFTestOutputFileName);
File.WriteAllBytes(testFile, bytes);
MessageBox.Show(String.Format("{0} written", PDFTestOutputFileName));
}
}
}
catch (DocumentException dex)
{
throw (dex);
}
catch (IOException ioex)
{
throw (ioex);
}
catch (Exception ex)
{
String exMsg = ex.Message;
MessageBox.Show(String.Format("Boo-boo!: {0}", ex.Message));
}
Why is my borderless table invisible or nonexistant?
UPDATE
Based on Bruno's answer, and applying it to the output that I really need, this works:
using (var ms = new MemoryStream())
{
using (var doc = new Document(PageSize.A4, 50, 50, 25, 25)) {
//Create a writer that's bound to our PDF abstraction and our stream
using (var writer = PdfWriter.GetInstance(doc, ms))
{
//Open the document for writing
doc.Open();
// Mimic the appearance of Direct_Payment.pdf
var courierBold11Font = FontFactory.GetFont(FontFactory.COURIER_BOLD, 11, BaseColor.BLACK);
var docTitle = new Paragraph("UCSC - Direct Payment Form", courierBold11Font);
doc.Add(docTitle);
var timesRoman9Font = FontFactory.GetFont("Times Roman", 9, BaseColor.BLACK);
var subTitle = new Paragraph("(not to be used for reimbursement of services)", timesRoman9Font);
doc.Add(subTitle);
var courier9RedFont = FontFactory.GetFont("Courier", 9, BaseColor.RED);
var importantNotice = new Paragraph("Important: Form must be filled out in Adobe Reader or Acrobat Professional 8.1 or above. To save completed forms, Acrobat Professional is required. For technical and accessibility assistance, contact the Campus Controller's Office.", courier9RedFont);
importantNotice.Leading = 0;
importantNotice.MultipliedLeading = 0.9F; // reduce the width between lines in the paragraph with these two settings
// Add a table
PdfPTable table = new PdfPTable(1);
PdfPCell cellImportantNote = new PdfPCell(importantNotice);
cellImportantNote.BorderWidth = PdfPCell.NO_BORDER;
table.WidthPercentage = 50;
table.HorizontalAlignment = Element.ALIGN_LEFT;
table.AddCell(cellImportantNote);
doc.Add(table);
doc.Close();
}
var bytes = ms.ToArray();
String PDFTestOutputFileName = String.Format("iTextSharp_{0}.pdf", DateTime.Now.ToShortTimeString());
PDFTestOutputFileName = PDFTestOutputFileName.Replace(":", "_");
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), PDFTestOutputFileName);
File.WriteAllBytes(testFile, bytes);
MessageBox.Show(String.Format("{0} written", PDFTestOutputFileName));
}
}
Please take a look at the SimpleTable7 example and compare the Java code with your [?] code:
This part is relevant:
PdfPCell cellImportantNote = new PdfPCell(importantNotice);
cellImportantNote.setColspan(5);
cellImportantNote.setBorder(PdfPCell.NO_BORDER);
table.addCell(cellImportantNote);
If I would convert your [?] code to Java, you'd have:
PdfPCell cellImportantNote = new PdfPCell(importantNotice);
cellImportantNote.setColspan(5);
cellImportantNote.setBorder(PdfPCell.NO_BORDER);
table.addCell(importantNotice);
Do you see the difference? You create a cellImportantNote instance, but you aren't using it anywhere. Instead of adding cellImportantNote to the table, you add the importantNotice paragraph.
This means that you are creating a table with 10 columns that has a single row of which only 6 cells are taken (because you have 1 cell with colspan 3, 1 cell with colspan 2 and 1 cell with colspan 1).
By default, iText doesn't render any rows that aren't complete, and since your table doesn't have any complete row, the table isn't being rendered.
If you look at the resulting PDF, simple_table7.pdf, you'll notice that I also added a second table. This table has only three columns, but it looks identical to the table you constructed. Instead of improper use of the colspan functionality, I defined relative widths for the three columns:
table = new PdfPTable(3);
table.setWidths(new int[]{3, 2, 5});
cell.setColspan(1);
table.addCell(cell);
cellCaveat.setColspan(1);
table.addCell(cellCaveat);
cellImportantNote.setColspan(1);
table.addCell(cellImportantNote);
document.add(table);
Note that I also avoid to use meaningless numbers. For instance, instead of:
cell.setHorizontalAlignment(0); // 0 means left
I use:
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
This way, people can read what this line means without having to depend on comments.
Furtermore, I replaced:
cell.setBorderWidth(0);
with:
cell.setBorder(PdfPCell.NO_BORDER);
That too, is only a matter of taste, but I think it's important if you want to keep your code maintainable.
I'm trying to create a PDF document that is essentially a list of users in a table format. I need the table to have checkboxes in it. So far, I have the table and the checkboxes separately but I cannot find a way to get the checkboxes in the table. I think I need to add them using the AddCell() method.
Here is my code:
static void Main(string[] args)
{
// create the document, filestream, writer
Document doc = new Document(PageSize.LETTER);
FileStream file = new FileStream(#"C:\Users\test\User List.pdf", FileMode.OpenOrCreate);
PdfWriter writer = PdfWriter.GetInstance(doc, file);
try
{
// metadata
doc.AddAuthor("Test User");
doc.AddCreator("Test Document");
doc.AddKeywords("Test Document");
doc.AddSubject("Test Document");
doc.AddTitle("Test Document - Test User");
// open up the PDF document
doc.Open();
PdfContentByte cb = writer.DirectContent;
Font _bf = new Font(Font.FontFamily.HELVETICA, 9);
// create a table
PdfPTable table = new PdfPTable(3);
PdfPCell cell = new PdfPCell(new Phrase("User List"));
PdfFormField field = PdfFormField.CreateCheckBox(writer);
field.SetWidget(new Rectangle(40, 500, 60, 530), PdfAnnotation.HIGHLIGHT_INVERT);
field.SetFieldFlags(PdfAnnotation.FLAGS_PRINT);
field.FieldName = "Delete";
writer.AddAnnotation(field);
cell.Colspan = 3;
cell.HorizontalAlignment = 0; //0 = left, 1 = center, 2 = right
cell.VerticalAlignment = 1;
table.AddCell("No.");
table.AddCell("Users");
table.AddCell("Delete");
// create form fields
PdfAppearance[] onOff = new PdfAppearance[2];
Rectangle rect;
PdfFormField checkbox;
RadioCheckField _checkbox;
onOff[0] = cb.CreateAppearance(10, 10);
onOff[0].Rectangle(1, 1, 8, 8);
onOff[0].Stroke();
onOff[1] = cb.CreateAppearance(10, 10);
onOff[1].SetRGBColorFill(255, 128, 128);
onOff[1].Rectangle(1, 1, 8, 8);
onOff[1].FillStroke();
onOff[1].MoveTo(1, 1);
onOff[1].LineTo(9, 9);
onOff[1].MoveTo(1, 9);
onOff[1].LineTo(9, 1);
onOff[1].Stroke();
for (int i = 0; i < 5; i++)
{
table.AddCell(i.ToString());
table.AddCell("User " + i);
//rect = new Rectangle(400, 675 - i*40, 415, 663 - i*40);
rect = new Rectangle(400, 735 - i * 40, 415, 723 - i * 40);
_checkbox = new RadioCheckField(writer, rect, "User "+(i+1), "Yes");
checkbox = _checkbox.CheckField;
checkbox.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", onOff[0]);
checkbox.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "On", onOff[1]);
writer.AddAnnotation(checkbox);
// this is where I am trying to add the checkbox to the table
// what can I add to AddCell() to make the checkbox show up?
table.AddCell();
//ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT, new Phrase("User " + (i + 1), _bf), 50, 665 - i * 40, 0);
}
cb = writer.DirectContent;
doc.Add(table);
}
catch(DocumentException dex)
{
throw (dex);
}
finally
{
// close
doc.Close();
writer.Close();
file.Close();
}
}
Is there any way to do this using iTextSharp? Maybe there is a better library to use?
I'll reference the iText website showing how to pass a field to a custom IPdfPCellEvent implementation and how to create that that custom class and recreate it below in C#.
First, create a class the implements the IPdfPCellEvent:
public class ChildFieldEvent : IPdfPCellEvent {
/** A parent field to which a child field has to be added. */
protected PdfFormField parent;
/** The child field that has to be added */
protected PdfFormField kid;
/** The padding of the field inside the cell */
protected float padding;
/**
* Creates a ChildFieldEvent.
* #param parent the parent field
* #param kid the child field
* #param padding a padding
*/
public ChildFieldEvent(PdfFormField parent, PdfFormField kid, float padding) {
this.parent = parent;
this.kid = kid;
this.padding = padding;
}
/**
* Add the child field to the parent, and sets the coordinates of the child field.
*/
public void CellLayout(PdfPCell cell, iTextSharp.text.Rectangle rect, PdfContentByte[] cb) {
parent.AddKid(kid);
kid.SetWidget(new iTextSharp.text.Rectangle(
rect.GetLeft(padding),
rect.GetBottom(padding),
rect.GetRight(padding),
rect.GetTop(padding)
),
PdfAnnotation.HIGHLIGHT_INVERT
);
}
}
Then just set the CellEvent on any cells that should have fields in them.
//File to create
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
//Standard PDF creation, nothing special here
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Create a root form object that we'll add "children" to. This way we don't have to add each "child" annotation to the writer
var root = PdfFormField.CreateEmpty(writer);
root.FieldName = "root";
//Create a two column table
var t = new PdfPTable(2);
//Add a basic cell
t.AddCell("First Name");
//Create our textfield, the rectangle that we're passing in is ignored and doesn't matter
var tf = new TextField(writer, new iTextSharp.text.Rectangle(0, 0), "first-name");
//Create a new cell
var cell = new PdfPCell();
//Set the cell event to our custom IPdfPCellEvent implementation
cell.CellEvent = new ChildFieldEvent(root, tf.GetTextField(), 1);
//Add the cell to our table
t.AddCell(cell);
//Add the table to the document
doc.Add(t);
//IMPORTANT! Add the root annotation to the writer which also adds all of the child annotations
writer.AddAnnotation(root);
//Clean up
doc.Close();
}
}
}
How to merge multiple pdf files (generated on run time) through ItextSharp then printing them.
I found the following link but that method requires the pdf names considering that the pdf files stored and this is not my case .
I have multiple reports i'll convert them to pdf files through this method :
private void AddReportToResponse(LocalReport followsReport)
{
string mimeType;
string encoding;
string extension;
string[] streams = new string[100];
Warning[] warnings = new Warning[100];
byte[] pdfStream = followsReport.Render("PDF", "", out mimeType, out encoding, out extension, out streams, out warnings);
//Response.Clear();
//Response.ContentType = mimeType;
//Response.AddHeader("content-disposition", "attachment; filename=Application." + extension);
//Response.BinaryWrite(pdfStream);
//Response.End();
}
Now i want to merge all those generated files (Bytes) in one pdf file to print it
If you want to merge source documents using iText(Sharp), there are two basic situations:
You really want to merge the documents, acquiring the pages in their original format, transfering as much of their content and their interactive annotations as possible. In this case you should use a solution based on a member of the Pdf*Copy* family of classes.
You actually want to integrate pages from the source documents into a new document but want the new document to govern the general format and don't care for the interactive features (annotations...) in the original documents (or even want to get rid of them). In this case you should use a solution based on the PdfWriter class.
You can find details in chapter 6 (especially section 6.4) of iText in Action — 2nd Edition. The Java sample code can be accessed here and the C#'ified versions here.
A simple sample using PdfCopy is Concatenate.java / Concatenate.cs. The central piece of code is:
byte[] mergedPdf = null;
using (MemoryStream ms = new MemoryStream())
{
using (Document document = new Document())
{
using (PdfCopy copy = new PdfCopy(document, ms))
{
document.Open();
for (int i = 0; i < pdf.Count; ++i)
{
PdfReader reader = new PdfReader(pdf[i]);
// loop over the pages in that document
int n = reader.NumberOfPages;
for (int page = 0; page < n; )
{
copy.AddPage(copy.GetImportedPage(reader, ++page));
}
}
}
}
mergedPdf = ms.ToArray();
}
Here pdf can either be defined as a List<byte[]> immediately containing the source documents (appropriate for your use case of merging intermediate in-memory documents) or as a List<String> containing the names of source document files (appropriate if you merge documents from disk).
An overview at the end of the referenced chapter summarizes the usage of the classes mentioned:
PdfCopy: Copies pages from one or more existing PDF documents. Major downsides: PdfCopy doesn’t detect redundant content, and it fails when concatenating forms.
PdfCopyFields: Puts the fields of the different forms into one form. Can be used to avoid the problems encountered with form fields when concatenating forms using PdfCopy. Memory use can be an issue.
PdfSmartCopy: Copies pages from one or more existing PDF documents. PdfSmartCopy is able to detect redundant content, but it needs more memory and CPU than PdfCopy.
PdfWriter: Generates PDF documents from scratch. Can import pages from other PDF documents. The major downside is that all interactive features of the imported page (annotations, bookmarks, fields, and so forth) are lost in the process.
I used iTextsharp with c# to combine pdf files. This is the code I used.
string[] lstFiles=new string[3];
lstFiles[0]=#"C:/pdf/1.pdf";
lstFiles[1]=#"C:/pdf/2.pdf";
lstFiles[2]=#"C:/pdf/3.pdf";
PdfReader reader = null;
Document sourceDocument = null;
PdfCopy pdfCopyProvider = null;
PdfImportedPage importedPage;
string outputPdfPath=#"C:/pdf/new.pdf";
sourceDocument = new Document();
pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create));
//Open the output file
sourceDocument.Open();
try
{
//Loop through the files list
for (int f = 0; f < lstFiles.Length-1; f++)
{
int pages =get_pageCcount(lstFiles[f]);
reader = new PdfReader(lstFiles[f]);
//Add pages of current file
for (int i = 1; i <= pages; i++)
{
importedPage = pdfCopyProvider.GetImportedPage(reader, i);
pdfCopyProvider.AddPage(importedPage);
}
reader.Close();
}
//At the end save the output file
sourceDocument.Close();
}
catch (Exception ex)
{
throw ex;
}
private int get_pageCcount(string file)
{
using (StreamReader sr = new StreamReader(File.OpenRead(file)))
{
Regex regex = new Regex(#"/Type\s*/Page[^s]");
MatchCollection matches = regex.Matches(sr.ReadToEnd());
return matches.Count;
}
}
Here is some code I pulled out of an old project I had. It was a web application but I was using iTextSharp to merge pdf files then print them.
public static class PdfMerger
{
/// <summary>
/// Merge pdf files.
/// </summary>
/// <param name="sourceFiles">PDF files being merged.</param>
/// <returns></returns>
public static byte[] MergeFiles(List<Stream> sourceFiles)
{
Document document = new Document();
MemoryStream output = new MemoryStream();
try
{
// Initialize pdf writer
PdfWriter writer = PdfWriter.GetInstance(document, output);
writer.PageEvent = new PdfPageEvents();
// Open document to write
document.Open();
PdfContentByte content = writer.DirectContent;
// Iterate through all pdf documents
for (int fileCounter = 0; fileCounter < sourceFiles.Count; fileCounter++)
{
// Create pdf reader
PdfReader reader = new PdfReader(sourceFiles[fileCounter]);
int numberOfPages = reader.NumberOfPages;
// Iterate through all pages
for (int currentPageIndex = 1; currentPageIndex <=
numberOfPages; currentPageIndex++)
{
// Determine page size for the current page
document.SetPageSize(
reader.GetPageSizeWithRotation(currentPageIndex));
// Create page
document.NewPage();
PdfImportedPage importedPage =
writer.GetImportedPage(reader, currentPageIndex);
// Determine page orientation
int pageOrientation = reader.GetPageRotation(currentPageIndex);
if ((pageOrientation == 90) || (pageOrientation == 270))
{
content.AddTemplate(importedPage, 0, -1f, 1f, 0, 0,
reader.GetPageSizeWithRotation(currentPageIndex).Height);
}
else
{
content.AddTemplate(importedPage, 1f, 0, 0, 1f, 0, 0);
}
}
}
}
catch (Exception exception)
{
throw new Exception("There has an unexpected exception" +
" occured during the pdf merging process.", exception);
}
finally
{
document.Close();
}
return output.GetBuffer();
}
}
/// <summary>
/// Implements custom page events.
/// </summary>
internal class PdfPageEvents : IPdfPageEvent
{
#region members
private BaseFont _baseFont = null;
private PdfContentByte _content;
#endregion
#region IPdfPageEvent Members
public void OnOpenDocument(PdfWriter writer, Document document)
{
_baseFont = BaseFont.CreateFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
_content = writer.DirectContent;
}
public void OnStartPage(PdfWriter writer, Document document)
{ }
public void OnEndPage(PdfWriter writer, Document document)
{ }
public void OnCloseDocument(PdfWriter writer, Document document)
{ }
public void OnParagraph(PdfWriter writer,
Document document, float paragraphPosition)
{ }
public void OnParagraphEnd(PdfWriter writer,
Document document, float paragraphPosition)
{ }
public void OnChapter(PdfWriter writer, Document document,
float paragraphPosition, Paragraph title)
{ }
public void OnChapterEnd(PdfWriter writer,
Document document, float paragraphPosition)
{ }
public void OnSection(PdfWriter writer, Document document,
float paragraphPosition, int depth, Paragraph title)
{ }
public void OnSectionEnd(PdfWriter writer,
Document document, float paragraphPosition)
{ }
public void OnGenericTag(PdfWriter writer, Document document,
Rectangle rect, string text)
{ }
#endregion
private float GetCenterTextPosition(string text, PdfWriter writer)
{
return writer.PageSize.Width / 2 - _baseFont.GetWidthPoint(text, 8) / 2;
}
}
I didn't write this, but made some modifications. I can't remember where I found it. After I merged the PDFs I would call this method to insert javascript to open the print dialog when the PDF is opened. If you change bSilent to true then it should print silently to their default printer.
public Stream addPrintJStoPDF(Stream thePDF)
{
MemoryStream outPutStream = null;
PRStream finalStream = null;
PdfDictionary page = null;
string content = null;
//Open the stream with iTextSharp
var reader = new PdfReader(thePDF);
outPutStream = new MemoryStream(finalStream.GetBytes());
var stamper = new PdfStamper(reader, (MemoryStream)outPutStream);
var jsText = "var res = app.setTimeOut('this.print({bUI: true, bSilent: false, bShrinkToFit: false});', 200);";
//Add the javascript to the PDF
stamper.JavaScript = jsText;
stamper.FormFlattening = true;
stamper.Writer.CloseStream = false;
stamper.Close();
//Set the stream to the beginning
outPutStream.Position = 0;
return outPutStream;
}
Not sure how well the above code is written since I pulled it from somewhere else and I haven't worked in depth at all with iTextSharp but I do know that it did work at merging PDFs that I was generating at runtime.
Tested with iTextSharp-LGPL 4.1.6:
public static byte[] ConcatenatePdfs(IEnumerable<byte[]> documents)
{
using (var ms = new MemoryStream())
{
var outputDocument = new Document();
var writer = new PdfCopy(outputDocument, ms);
outputDocument.Open();
foreach (var doc in documents)
{
var reader = new PdfReader(doc);
for (var i = 1; i <= reader.NumberOfPages; i++)
{
writer.AddPage(writer.GetImportedPage(reader, i));
}
writer.FreeReader(reader);
reader.Close();
}
writer.Close();
outputDocument.Close();
var allPagesContent = ms.GetBuffer();
ms.Flush();
return allPagesContent;
}
}
To avoid the memory issues mentioned, I used file stream instead of memory stream(mentioned in ITextSharp Out of memory exception merging multiple pdf) to merge pdf files:
var parentDirectory = Directory.GetParent(SelectedDocuments[0].FilePath);
var savePath = parentDirectory + "\\MergedDocument.pdf";
using (var fs = new FileStream(savePath, FileMode.Create))
{
using (var document = new Document())
{
using (var pdfCopy = new PdfCopy(document, fs))
{
document.Open();
for (var i = 0; i < SelectedDocuments.Count; i++)
{
using (var pdfReader = new PdfReader(SelectedDocuments[i].FilePath))
{
for (var page = 0; page < pdfReader.NumberOfPages;)
{
pdfCopy.AddPage(pdfCopy.GetImportedPage(pdfReader, ++page));
}
}
}
}
}
}
****/*For Multiple PDF Print..!!*/****
<button type="button" id="btnPrintMultiplePdf" runat="server" class="btn btn-primary btn-border btn-sm"
onserverclick="btnPrintMultiplePdf_click">
<i class="fa fa-file-pdf-o"></i>Print Multiple pdf</button>
protected void btnPrintMultiplePdf_click(object sender, EventArgs e)
{
if (ValidateForMultiplePDF() == true)
{
#region Declare Temp Variables..!!
CheckBox chkList = new CheckBox();
HiddenField HidNo = new HiddenField();
string Multi_fofile, Multi_listfile;
Multi_fofile = Multi_listfile = "";
Multi_fofile = Server.MapPath("PDFRNew");
#endregion
for (int i = 0; i < grdRnew.Rows.Count; i++)
{
#region Find Grd Controls..!!
CheckBox Chk_One = (CheckBox)grdRnew.Rows[i].FindControl("chkOne");
Label lbl_Year = (Label)grdRnew.Rows[i].FindControl("lblYear");
Label lbl_No = (Label)grdRnew.Rows[i].FindControl("lblCode");
#endregion
if (Chk_One.Checked == true)
{
HidNo .Value = llbl_No .Text.Trim()+ lbl_Year .Text;
if (File.Exists(Multi_fofile + "\\" + HidNo.Value.ToString() + ".pdf"))
{
#region Get Multiple Files Name And Paths..!!
if (Multi_listfile != "")
{
Multi_listfile = Multi_listfile + ",";
}
Multi_listfile = Multi_listfile + Multi_fofile + "\\" + HidNo.Value.ToString() + ".pdf";
#endregion
}
}
}
#region For Generate Multiple Pdf..!!
if (Multi_listfile != "")
{
String[] Multifiles = Multi_listfile.Split(',');
string DestinationFile = Server.MapPath("PDFRNew") + "\\Multiple.Pdf";
MergeFiles(DestinationFile, Multifiles);
Response.ContentType = "pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=\"" + DestinationFile + "\"");
Response.TransmitFile(DestinationFile);
Response.End();
}
else
{
}
#endregion
}
}
private void MergeFiles(string DestinationFile, string[] SourceFiles)
{
try
{
int f = 0;
/**we create a reader for a certain Document**/
PdfReader reader = new PdfReader(SourceFiles[f]);
/**we retrieve the total number of pages**/
int n = reader.NumberOfPages;
/**Console.WriteLine("There are " + n + " pages in the original file.")**/
/**Step 1: creation of a document-object**/
Document document = new Document(reader.GetPageSizeWithRotation(1));
/**Step 2: we create a writer that listens to the Document**/
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(DestinationFile, FileMode.Create));
/**Step 3: we open the Document**/
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
int rotation;
/**Step 4: We Add Content**/
while (f < SourceFiles.Length)
{
int i = 0;
while (i < n)
{
i++;
document.SetPageSize(reader.GetPageSizeWithRotation(i));
document.NewPage();
page = writer.GetImportedPage(reader, i);
rotation = reader.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
/**Console.WriteLine("Processed page " + i)**/
}
f++;
if (f < SourceFiles.Length)
{
reader = new PdfReader(SourceFiles[f]);
/**we retrieve the total number of pages**/
n = reader.NumberOfPages;
/**Console.WriteLine("There are"+n+"pages in the original file.")**/
}
}
/**Step 5: we Close the Document**/
document.Close();
}
catch (Exception e)
{
string strOb = e.Message;
}
}
private bool ValidateForMultiplePDF()
{
bool chkList = false;
foreach (GridViewRow gvr in grdRnew.Rows)
{
CheckBox Chk_One = (CheckBox)gvr.FindControl("ChkSelectOne");
if (Chk_One.Checked == true)
{
chkList = true;
}
}
if (chkList == false)
{
divStatusMsg.Style.Add("display", "");
divStatusMsg.Attributes.Add("class", "alert alert-danger alert-dismissable");
divStatusMsg.InnerText = "ERROR !!...Please Check At Least On CheckBox.";
grdRnew.Focus();
set_timeout();
return false;
}
return true;
}
I have a class that build the content for my table of contents and that works, fine and dandy.
Here's the code:
public void Build(string center,IDictionary<string,iTextSharp.text.Image> images)
{
iTextSharp.text.Image image = null;
XPathDocument rapportTekst = new XPathDocument(Application.StartupPath + #"..\..\..\RapportTemplates\RapportTekst.xml");
XPathNavigator nav = rapportTekst.CreateNavigator();
XPathNodeIterator iter;
iter = nav.Select("//dokument/brevhoved");
iter.MoveNext();
var logo = iTextSharp.text.Image.GetInstance(iter.Current.GetAttribute("url", ""));
iter = nav.Select("//dokument/gem_som");
iter.MoveNext();
string outputPath = iter.Current.GetAttribute("url", "")+center+".pdf";
iter = nav.Select("//dokument/titel");
iter.MoveNext();
this.titel = center;
Document document = new Document(PageSize.A4, 30, 30, 100, 30);
var outputStream = new FileStream(outputPath, FileMode.Create);
var pdfWriter = PdfWriter.GetInstance(document, outputStream);
pdfWriter.SetLinearPageMode();
var pageEventHandler = new PageEventHandler();
pageEventHandler.ImageHeader = logo;
pdfWriter.PageEvent = pageEventHandler;
DateTime timeOfReport = DateTime.Now.AddMonths(-1);
pageWidth = document.PageSize.Width - (document.LeftMargin + document.RightMargin);
pageHight = document.PageSize.Height - (document.TopMargin + document.BottomMargin);
document.Open();
var title = new Paragraph(titel, titleFont);
title.Alignment = Element.ALIGN_CENTER;
document.Add(title);
List<TableOfContentsEntry> _contentsTable = new List<TableOfContentsEntry>();
nav.MoveToRoot();
iter = nav.Select("//dokument/indhold/*");
Chapter chapter = null;
int chapterCount = 1;
while (iter.MoveNext())
{
_contentsTable.Add(new TableOfContentsEntry("Test", pdfWriter.CurrentPageNumber.ToString()));
XPathNodeIterator innerIter = iter.Current.SelectChildren(XPathNodeType.All);
chapter = new Chapter("test", chapterCount);
while(innerIter.MoveNext())
{
if (innerIter.Current.Name.ToString().ToLower().Equals("billede"))
{
image = images[innerIter.Current.GetAttribute("navn", "")];
image.Alignment = Image.ALIGN_CENTER;
image.ScaleToFit(pageWidth, pageHight);
chapter.Add(image);
}
if (innerIter.Current.Name.ToString().ToLower().Equals("sektion"))
{
string line = "";
var afsnit = new Paragraph();
line += (innerIter.Current.GetAttribute("id", "") + " ");
innerIter.Current.MoveToFirstChild();
line += innerIter.Current.Value;
afsnit.Add(line);
innerIter.Current.MoveToNext();
afsnit.Add(innerIter.Current.Value);
chapter.Add(afsnit);
}
}
chapterCount++;
document.Add(chapter);
}
document = CreateTableOfContents(document, pdfWriter, _contentsTable);
document.Close();
}
I'm then calling the method CreateTableOfContents(), and as such it is doing what it is supposed to do. Here's the code for the method:
public Document CreateTableOfContents(Document _doc, PdfWriter _pdfWriter, List<TableOfContentsEntry> _contentsTable)
{
_doc.NewPage();
_doc.Add(new Paragraph("Table of Contents", FontFactory.GetFont("Arial", 18, Font.BOLD)));
_doc.Add(new Chunk(Environment.NewLine));
PdfPTable _pdfContentsTable = new PdfPTable(2);
foreach (TableOfContentsEntry content in _contentsTable)
{
PdfPCell nameCell = new PdfPCell(_pdfContentsTable);
nameCell.Border = Rectangle.NO_BORDER;
nameCell.Padding = 6f;
nameCell.Phrase = new Phrase(content.Title);
_pdfContentsTable.AddCell(nameCell);
PdfPCell pageCell = new PdfPCell(_pdfContentsTable);
pageCell.Border = Rectangle.NO_BORDER;
pageCell.Padding = 6f;
pageCell.Phrase = new Phrase(content.Page);
_pdfContentsTable.AddCell(pageCell);
}
_doc.Add(_pdfContentsTable);
_doc.Add(new Chunk(Environment.NewLine));
/** Reorder pages so that TOC will will be the second page in the doc
* right after the title page**/
int toc = _pdfWriter.PageNumber - 1;
int total = _pdfWriter.ReorderPages(null);
int[] order = new int[total];
for (int i = 0; i < total; i++)
{
if (i == 0)
{
order[i] = 1;
}
else if (i == 1)
{
order[i] = toc;
}
else
{
order[i] = i;
}
}
_pdfWriter.ReorderPages(order);
return _doc;
}
The problem is however. I want to insert a page break before the table of contents, for the sake of reordering the pages, so that the table of contents is the first page, naturally. But the output of the pdf-file is not right.
Here's a picture of what it looks like:
It seems like the _doc.NewPage() in the CreateTableOfContents() method does not execute correctly. Meaning that the image and the table of contents is still on the same page when the method starts the reordering of pages.
EDIT: To clarify the above, the _doc.NewPage() gets executed, but the blank page is added after the picture and the table of contents.
I've read a couple of places that this could be because one is trying to insert a new page after an already blank page. But this is not the case.
I'll just link to the pdf files aswell, to better illustrate the problem.
The pdf with table of contents: with table of contents
The pdf without table of contents: without table of contents
Thank you in advance for your help :)
I am trying to display the "✔" character in a PDF using iTextSharp. However the character won't show up on the created PDF. Please help me on this.
Phrase phrase = new Phrase("A check mark: ");
Font zapfdingbats = new Font(Font.FontFamily.ZAPFDINGBATS);
phrase.Add(new Chunk("\u0033", zapfdingbats));
phrase.Add(" and more text");
document.Add(phrase);
Font Wingdings prints this character instead of "o".
You need to connect this font to your application, then apply this font to letter and embedd the font into pdf for compatibility.
This is my function (not cleaned) that I have used in one of my projects a while back.
please clean it up, but it has some essential features that you need. (I had my custom fonts (font1.ttf and font2.ttf) copied in the project directory)
I am hoping it will help you.
public void StartConvert(String originalFile, String newFile)
{
Document myDocument = new Document(PageSize.LETTER);
PdfWriter.GetInstance(myDocument, new FileStream(newFile, FileMode.Create));
myDocument.Open();
int totalfonts = FontFactory.RegisterDirectory("C:\\WINDOWS\\Fonts");
iTextSharp.text.Font content = FontFactory.GetFont("Pea Heather's Handwriting", 13);//13
iTextSharp.text.Font header = FontFactory.GetFont("assign", 16); //16
BaseFont customfont = BaseFont.CreateFont(#"font1.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
Font font = new Font(customfont, 13);
string s = " ";
myDocument.Add(new Paragraph(s, font));
BaseFont customfont2 = BaseFont.CreateFont(#"font2.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
Font font2 = new Font(customfont2, 16);
string s2 = " ";
myDocument.Add(new Paragraph(s2, font2));
try
{
try
{
using (StreamReader sr = new StreamReader(originalFile))
{
// Read and display lines from the file until the end of
// the file is reached.
String line;
while ((line = sr.ReadLine()) != null)
{
String newTempLine = "";
String[] textArray;
textArray = line.Split(' ');
newTempLine = returnSpaces(RandomNumber(0, 6)) + newTempLine;
int counterMax = RandomNumber(8, 12);
int counter = 0;
foreach (String S in textArray)
{
if (counter == counterMax)
{
Paragraph P = new Paragraph(newTempLine + Environment.NewLine, font);
P.Alignment = Element.ALIGN_LEFT;
myDocument.Add(P);
newTempLine = "";
newTempLine = returnSpaces(RandomNumber(0, 6)) + newTempLine;
}
newTempLine = newTempLine + returnSpaces(RandomNumber(1, 5)) + S;
counter++;
}
Paragraph T = new Paragraph(newTempLine, font2);
T.Alignment = Element.ALIGN_LEFT;
myDocument.Add(T);
}
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
}
catch (DocumentException de)
{
Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
Console.Error.WriteLine(ioe.Message);
}
try
{
myDocument.Close();
}
catch { }
}
Define font at master
protected static Font ZAPFDINGBATS(float size, bool bold = false, bool italic = false, bool underline = false, Color color = null)
=> new(StandardFonts.ZAPFDINGBATS, size, bold, italic, underline, color);
declare font
private readonly Font ZapFont = ZAPFDINGBATS(10, bold: false, color: ColorConstants.BLACK);
private readonly Action<Cell> _cellRight = cell => cell.RemoveBorder().SetTextAlignment(TextAlignment.RIGHT);
Use
document.AddTable(
columns: new float[1]
{
100
},
table => table.SetWidth(document.GetPageEffectiveArea(PageSize).GetWidth())
.SetMargins(0, 0, 0, 0)
.AddCell(model.IsTrue ? "4" : "o", ZapFont, _cellRight );
This worked for me:
pdfStamper.FormFlattening = true;