Adding a new page using iTextSharp - c#

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

Related

Why is my table not being generated on my PDF file using iTextSharp?

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.

Adding a Table into the Footer of a PDF

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

C# Open XML HTML to DOCX Spacing

I've been working on my site, and trying to create an Export to Word. The export works well, converting HTML string to DOCX.
I'm trying to figure out how I can adjust the Line Spacing. By Default Word is adding 8pt Spacing After and setting the Line Spacing to double. I would prefer 0 and Single.
Here is the Function I created to Save a Word Document:
private static void SaveDOCX(string fileName, string BodyText, bool isLandScape, double rMargin, double lMargin, double bMargin, double tMargin)
{
string htmlSectionID = "Sect1";
//Creating a word document using the the Open XML SDK 2.0
WordprocessingDocument document = WordprocessingDocument.Create(fileName, WordprocessingDocumentType.Document);
//create a paragraph
MainDocumentPart mainDocumenPart = document.AddMainDocumentPart();
mainDocumenPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();
Body documentBody = new Body();
mainDocumenPart.Document.Append(documentBody);
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<html><head></head><body>" + BodyText + "</body></html>"));
// Create alternative format import part.
AlternativeFormatImportPart formatImportPart = mainDocumenPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, htmlSectionID);
//ms.Seek(0, SeekOrigin.Begin);
// Feed HTML data into format import part (chunk).
formatImportPart.FeedData(ms);
AltChunk altChunk = new AltChunk();
altChunk.Id = htmlSectionID;
mainDocumenPart.Document.Body.Append(altChunk);
/*
inch equiv = 1440 (1 inch margin)
*/
double width = 8.5 * 1440;
double height = 11 * 1440;
SectionProperties sectionProps = new SectionProperties();
PageSize pageSize;
if (isLandScape)
{
pageSize = new PageSize() { Width = (UInt32Value)height, Height = (UInt32Value)width, Orient = PageOrientationValues.Landscape };
}
else
{
pageSize = new PageSize() { Width = (UInt32Value)width, Height = (UInt32Value)height, Orient = PageOrientationValues.Portrait };
}
rMargin = rMargin * 1440;
lMargin = lMargin * 1440;
bMargin = bMargin * 1440;
tMargin = tMargin * 1440;
PageMargin pageMargin = new PageMargin() { Top = (Int32)tMargin, Right = (UInt32Value)rMargin, Bottom = (Int32)bMargin, Left = (UInt32Value)lMargin, Header = (UInt32Value)360U, Footer = (UInt32Value)360U, Gutter = (UInt32Value)0U };
sectionProps.Append(pageSize);
sectionProps.Append(pageMargin);
mainDocumenPart.Document.Body.Append(sectionProps);
//Saving/Disposing of the created word Document
document.MainDocumentPart.Document.Save();
document.Dispose();
}
In searching, I found this code:
SpacingBetweenLines spacing = new SpacingBetweenLines() { Line = "240", LineRule = LineSpacingRuleValues.Auto, Before = "0", After = "0" };
I've placed it many places in my function, but I can't seem to find the correct place to Append this setting.
I worked on the function trying to set the spacing in code, but wasn't able to remove the spacing. I decided to try creating a Template Word Document and setting the spacing in that document.
I copy the template.docx file, creating the one I will use, then use the adjusted function below to add the HTML string:
private static void SaveDOCX(string fileName, string BodyText, bool isLandScape, double rMargin, double lMargin, double bMargin, double tMargin)
{
WordprocessingDocument document = WordprocessingDocument.Open(fileName, true);
MainDocumentPart mainDocumenPart = document.MainDocumentPart;
//Place the HTML String into a MemoryStream Object
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<html><head></head><body>" + BodyText + "</body></html>"));
//Assign an HTML Section for the String Text
string htmlSectionID = "Sect1";
// Create alternative format import part.
AlternativeFormatImportPart formatImportPart = mainDocumenPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, htmlSectionID);
// Feed HTML data into format import part (chunk).
formatImportPart.FeedData(ms);
AltChunk altChunk = new AltChunk();
altChunk.Id = htmlSectionID;
//Clear out the Document Body and Insert just the HTML string. (This prevents an empty First Line)
mainDocumenPart.Document.Body.RemoveAllChildren();
mainDocumenPart.Document.Body.Append(altChunk);
/*
Set the Page Orientation and Margins Based on Page Size
inch equiv = 1440 (1 inch margin)
*/
double width = 8.5 * 1440;
double height = 11 * 1440;
SectionProperties sectionProps = new SectionProperties();
PageSize pageSize;
if (isLandScape)
pageSize = new PageSize() { Width = (UInt32Value)height, Height = (UInt32Value)width, Orient = PageOrientationValues.Landscape };
else
pageSize = new PageSize() { Width = (UInt32Value)width, Height = (UInt32Value)height, Orient = PageOrientationValues.Portrait };
rMargin = rMargin * 1440;
lMargin = lMargin * 1440;
bMargin = bMargin * 1440;
tMargin = tMargin * 1440;
PageMargin pageMargin = new PageMargin() { Top = (Int32)tMargin, Right = (UInt32Value)rMargin, Bottom = (Int32)bMargin, Left = (UInt32Value)lMargin, Header = (UInt32Value)360U, Footer = (UInt32Value)360U, Gutter = (UInt32Value)0U };
sectionProps.Append(pageSize);
sectionProps.Append(pageMargin);
mainDocumenPart.Document.Body.Append(sectionProps);
//Saving/Disposing of the created word Document
document.MainDocumentPart.Document.Save();
document.Dispose();
}
By using the template file, the line spacing is correct.
For those that might find this function useful, here is the code that calls the function:
string filePath = "~/Content/Exports/Temp/";
string WordTemplateFile = HttpContext.Current.Server.MapPath("/Content/Templates/WordTemplate.docx");
string DestinationPath = HttpContext.Current.Server.MapPath(filePath);
string NewFileName = DOCXFileName + ".docx";
string destFile = System.IO.Path.Combine(DestinationPath, NewFileName);
System.IO.File.Copy(WordTemplateFile, destFile, true);
SaveDOCX(destFile, HTMLString, isLandScape, rMargin, lMargin, bMargin, tMargin);
You can't change the formatting because your code is only inserting HTML into a Word doc. To change the formatting, the HTML text needs to be converted to regular text and added to the Word doc as such. I was in a similar issue and using the HtmlToOpenXml library makes this quick and simple.
using HtmlToOpenXml;
Then the function:
protected virtual void createWord()
{
string html = "*myHtml*";
// Create WordProcessingDocument
WordprocessingDocument doc = WordprocessingDocument.Create(ms, WordprocessingDocumentType.Document);
MainDocumentPart mainPart = doc.MainDocumentPart;
if (mainPart == null)
mainPart = doc.AddMainDocumentPart();
Document document = doc.MainDocumentPart.Document;
if (document == null)
document = mainPart.Document = new Document();
Body body = mainPart.Document.Body;
if (body == null)
body = mainPart.Document.Body = new Body(new SectionProperties(new PageMargin() { Top = 1440, Right = 1440U, Bottom = 1440, Left = 1440U, Header = 720U, Footer = 720U, Gutter = 0U }));
// Convert Html to OpenXml
HtmlConverter converter = new HtmlConverter(mainPart);
converter.ParseHtml(html);
// Reformat paragraphs
ParagraphProperties pProps = new ParagraphProperties(new SpacingBetweenLines() { Line = "240", LineRule = LineSpacingRuleValues.Auto, Before = "0", After = "0" });
var paragraphs = doc.MainDocumentPart.Document.Body.Descendants<Paragraph>().ToList();
foreach (Paragraph p in paragraphs)
{
if (p != null)
p.PrependChild(pProps.CloneNode(true));
}
// Close the document handle
doc.Close();
}

Adding form elements to a table with iTextSharp

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

PDFNet trying to add a text not working

I am basically trying out PDFNet and tweaking one of the samples of PDFNet. Here is the code:
PDFNet.Initialize();
// Relative path to the folder containing test files.
string input_path = "../../../../TestFiles/";
string output_path = "../../../../TestFiles/Output/";
PDFDoc doc = new PDFDoc(input_path + "form1.pdf");
for (int index = 1; index <= doc.GetPageCount(); index++)
{
Page page = doc.GetPage(index);
ElementBuilder eb = new ElementBuilder(); // ElementBuilder is used to build new Element objects
eb.Reset(); // Reset GState to default
ElementWriter writer = new ElementWriter(); // ElementWriter is used to write Elements to the page
writer.Begin(page);
// Begin writing a block of text
string data = "Page " + index;
Element element = eb.CreateTextRun(data, Font.Create(doc, Font.StandardType1Font.e_times_roman, true), 100.0);
element.SetTextMatrix(10, 0, 0, 10, 100, 100);
GState gstate = element.GetGState();
gstate.SetTextRenderMode(GState.TextRenderingMode.e_stroke_text);
gstate.SetStrokeColorSpace(pdftron.PDF.ColorSpace.CreateDeviceRGB());
gstate.SetStrokeColor(new pdftron.PDF.ColorPt(1, 0, 0));
writer.WriteElement(element);
writer.End();
writer.Dispose(); // save changes to the current page
}
doc.Save(output_path + "element_builder.pdf", SDFDoc.SaveOptions.e_linearized);
doc.Close();
But problem is, no text is added to element_builder.pdf. It is just copied as it is and looks same as form1.pdf. Can anybody help me out?
This is the link to PDFNet http://www.pdftron.com/pdfnet/downloads.html
I am using 64 bit version for .Net 4.0
It seems that you are missing the calls eb.CreateTextBegin() and eb.CreateTextEnd(). You should try something like this:
PDFNet.Initialize();
// Relative path to the folder containing test files.
string input_path = "../../../../TestFiles/";
string output_path = "../../../../TestFiles/Output/";
PDFDoc doc = new PDFDoc(input_path + "form1.pdf");
ElementWriter writer = new ElementWriter();
ElementBuilder eb = new ElementBuilder();
for (int index = 1; index <= doc.GetPageCount(); index++)
{
Page page = doc.GetPage(index);
writer.Begin(page);
eb.Reset();
// Begin writing a block of text
string data = "Page " + index;
Element element = eb.CreateTextBegin(Font.Create(doc, Font.StandardType1Font.e_times_roman, true), 10.0);
writer.WriteElement(element);
eb.CreateTextRun(data);
element.SetTextMatrix(10, 0, 0, 10, 100, 100);
GState gstate = element.GetGState();
gstate.SetTextRenderMode(GState.TextRenderingMode.e_fill_text);
gstate.SetStrokeColorSpace(pdftron.PDF.ColorSpace.CreateDeviceRGB());
gstate.SetStrokeColor(new pdftron.PDF.ColorPt(1, 0, 0));
writer.WriteElement(element);
writer.WriteElement(eb.CreateTextEnd());
writer.End();
}
writer.Dispose();
eb.Dispose();
doc.Save(output_path + "element_builder.pdf", SDFDoc.SaveOptions.e_linearized);
doc.Close();
Btw. a possibly simpler way to add text to an existing page may be to use 'pdftron.PDF.Stamper' as shown in Stamper sample.

Categories

Resources