I have an HTML table in a view. I'm using ITextSharp 4 to convert the HTML to a PDF using the htmlParser. The table spans multiple pages. How do I get it to show the header on each page? Is there some setting I can turn on in HTML so that ITextSharp can recognise it?
I don't have access to iTextSharp 4.0 but since the HTML parser writes directly to the document I'm not sure if it would be possible without modify the original source. Is it an option to upgrade to 5.0 which completely replaced the HtmlParser with a much more robust HTMLWorker object?
To have a PdfPTable's headers span multiple page you need to set its HeaderRows property to the number of rows in your header. Unfortunately if you're using the HTMLParser or the HTMLWorker they do not currently treat THEAD and TH tags differently than TBODY and TD tags. The solution is to modify the PdfPTable sometime after parsing but before being written to the document. I don't have 4.0 available here but in 5.1.1.0 using the HTMLWorker you can easily do that and manually set the HeaderRows property:
//Output file
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Table.pdf");
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (Document doc = new Document(PageSize.LETTER))
{
using (PdfWriter w = PdfWriter.GetInstance(doc, fs))
{
doc.Open();
doc.NewPage();
//Create some long text to force a new page
string longText = String.Concat(Enumerable.Repeat("Lorem ipsum.", 40));
//Create our table using both THEAD and TH which iTextSharp currently ignores
string html = "<table>";
html += "<thead><tr><th>Header Row 1/Cell 1</th><th>Header Row 1/Cell 2</th></tr><tr><th>Header Row 2/Cell 1</th><th>Header Row 2/Cell 2</th></tr></thead>";
html += "<tbody>";
for (int i = 3; i < 20; i++)
{
html += "<tr>";
html += String.Format("<td>Data Row {0}</td>", i);
html += String.Format("<td>{0}</td>", longText);
html += "</tr>";
}
html += "</tbody>";
html += "</table>";
using (StringReader sr = new StringReader(html))
{
//Get our list of elements (only 1 in this case)
List<IElement> elements = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(sr, null);
foreach (IElement el in elements)
{
//If the element is a table manually set its header row count
if (el is PdfPTable)
{
((PdfPTable)el).HeaderRows = 2;
}
doc.Add(el);
}
}
doc.Close();
}
}
}
you should just be able to set: table.HeaderRows = 1;
this will repeat the header on each page.
Apply the "repeat-header" style, and set to "yes", like so:
<table style="repeat-header:yes;">
Related
I'm using iText 7 for printing some text in List (in Hebrew) to PDF file, but while printing the Hebrew characters are printed in a reverse way.
The input given was "קניון אם הדרך" while the data printed in PDF is "ךרדה םא ןוינק"
I have set the font encoding and the base direction for the elements but still the characters are printed in the reverse order.
Code to print list into the table in PDF:
public void PrintListData(string filename)
{
var writer = new PdfWriter(filename);
PdfDocument pdfDoc = new PdfDocument(writer);
Document doc = new Document(pdfDoc, PageSize.A4);
SetFont(doc);
Table table = new Table(UnitValue.CreatePercentArray(2)).UseAllAvailableWidth();
table.SetTextAlignment(TextAlignment.RIGHT);
//table.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
var index = 1;
foreach (var item in _data)
{
var para = new Paragraph(item);
para.SetTextAlignment(TextAlignment.RIGHT);
//para.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
table.AddCell(index.ToString());
table.AddCell(para);
index++;
}
doc.Add(table);
doc.Close();
Process.Start(filename);
}
Set font function
void SetFont(Document doc)
{
FontSet _defaultFontSet = new FontSet();
var fontFolders = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
_defaultFontSet.AddFont(System.IO.Path.Combine(fontFolders, "arial.ttf"), PdfEncodings.IDENTITY_H);
_defaultFontSet.AddFont(System.IO.Path.Combine(fontFolders, "arialbd.ttf"), PdfEncodings.IDENTITY_H);
doc.SetFontProvider(new FontProvider(_defaultFontSet));
doc.SetProperty(Property.FONT, new String[] { "MyFontFamilyName" });
//doc.SetProperty(Property.BASE_DIRECTION, BaseDirection.RIGHT_TO_LEFT);
}
I'm not sure to where should we set the text direction to print RTL.
I have a pdf document where I am filling all the values using the below code.
using(MemoryStream ms = new MemoryStream())
{
// Fill the PDF with the XFA
using(PdfStamper stamper = new PdfStamper(oInPDF, ms))
{
stamper.Writer.CloseStream = false;
XfaForm.SetXfa(oXFA, stamper.Reader, stamper.Writer);
}
// Code for Flatten the filled PDF.
}
I am trying to draw a box in red around the value displayed to highlight when the values are not in the expected range.
I would like to know, how do I locate the position of a control on a pdf page using iTextSharp and C#.
Any help or info on this, much appreciated.
Many Thanks.
Finally managed to draw borders around controls with below code.
XmlDocument newXMLDoc = new XmlDocument();
newXMLDoc.LoadXml(#"<border><edge thickness=""1.3mm""><color value=""0, 0, 255""/></edge></border>");
if (Rs.Rows.Count > 0)
{
foreach (DataRow query in Rs.Rows)
{
if(isRET)
{
if (oXFA.DomDocument.SelectSingleNode("//t:*[#name='" + Rs[0] + "']", oNameSpace) != null)
{
XmlNode newNode =
oXFA.DomDocument.ImportNode(newXMLDoc.SelectSingleNode("border"), true);
oXFA.DomDocument.SelectSingleNode("//t:*[#name='" + Rs[0] + "']", oNameSpace).AppendChild(newNode);
}
}
}
}
I have a report that I'm trying to generate using iTextSharp that includes html text entered by the user using tinymce on my web page. I then have a report and I want to insert a phrase that uses their markup.
While basic markup such as bold and underline work, lists, indents, alignment do not. Any suggestions short of writing my own little html to pdf parser?
My code:
internal static Phrase GetPhraseFromHtml(string html, string fontName, int fontSize)
{
var returnPhrase = new Phrase();
html.Replace(Environment.NewLine, String.Empty);
//the string has to be well formated html in order to work and has to specify the font since
//specifying the font in the phrase overrides the formatting of the html tags.
string pTag = string.Format("<p style='font-size: {0}; font-family:{1}'>", fontSize, fontName);
if (html.StartsWith("<p>"))
{
html = html.Replace("<p>", pTag);
}
else
{
html = pTag + html + "</p>";
}
html
= "<html><body>"
+ html
+ "</body></html>";
using (StringWriter sw = new StringWriter())
{
using (System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(sw))
{
var xmlWorkerHandler = new XmlWorkerHandler();
//Bind a reader to our text
using (TextReader textReader = new StringReader(html))
{
//Parse
XMLWorkerHelper.GetInstance().ParseXHtml(xmlWorkerHandler, textReader);
}
var addPhrase = new Phrase();
var elementText = new StringBuilder();
bool firstElement = true;
//Loop through each element
foreach (var element in xmlWorkerHandler.elements)
{
if (firstElement)
{
firstElement = false;
}
else
{
addPhrase.Add(new Chunk("\n"));
}
//Loop through each chunk in each element
foreach (var chunk in element.Chunks)
{
addPhrase.Add(chunk);
}
returnPhrase.Add(addPhrase);
addPhrase = new Phrase();
}
return returnPhrase;
}
}
}
I have a sharepoint hosted application which contains a docx template file which has mailmerge fields like << Customer_Name >>.
It is a 1 Page document. I have to create a new docx file from this template which might contain multiple pages depending upon the number of customer. The content will be repeated and the merge fields has to be replaced with data from datatable for each page.
I tried using AltChunk but after using this method i cannot find and replace the text fields.
using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = template.MainDocumentPart;
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i][1].ToString() != "")
{
ReplaceText(mainPart, "«customer_Address»", dt.Rows[i][1].ToString());
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 15);
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
chunk.FeedData(filestream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
mainPart.Document.Save();
}
}
I am using ReplaceText Method to Replace text from paragraph.
private static void ReplaceText(MainDocumentPart docPart, string match, string value)
{
var body = docPart.Document.Body;
foreach (var text in body.Descendants<Text>())
{
if (text.Text.Contains(match))
{
text.Text = text.Text.Replace(match, value);
}
}
}
This ReplaceText works fine for origional mainPart but does nothing for text added using AltChunk.
What would be easier way to generate multi page document in my case?
I have a List<object> and this list contains thousands of record. I want to generated pdf using itextsharp. and Pdfptable to generated pdf it is working fine, but but I want only 10 records per page in pdf.
How can I do it?
Another way to set the number of rows per page:
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace RowsCountSample
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();
var table1 = new PdfPTable(3);
table1.HeaderRows = 2;
table1.FooterRows = 1;
//header row
var headerCell = new PdfPCell(new Phrase("header"));
headerCell.Colspan = 3;
headerCell.HorizontalAlignment = Element.ALIGN_CENTER;
table1.AddCell(headerCell);
//footer row
var footerCell = new PdfPCell(new Phrase("footer"));
footerCell.Colspan = 3;
footerCell.HorizontalAlignment = Element.ALIGN_CENTER;
table1.AddCell(footerCell);
//adding some rows
for (int i = 0; i < 70; i++)
{
//adds a new row
table1.AddCell(new Phrase("Cell[0], Row[" + i + "]"));
table1.AddCell(new Phrase("Cell[1], Row[" + i + "]"));
table1.AddCell(new Phrase("Cell[2], Row[" + i + "]"));
//sets the number of rows per page
if (i > 0 && table1.Rows.Count % 7 == 0)
{
pdfDoc.Add(table1);
table1.DeleteBodyRows();
pdfDoc.NewPage();
}
}
pdfDoc.Add(table1);
}
//open the final file with adobe reader for instance.
Process.Start("Test.pdf");
}
}
}
In the most recent version of iTextSharp (5.3.3), new functionality was added allowing you to define breakpoints: SetBreakPoints(int[] breakPoints)
If you define an array of multiples of 10, you can use this to get the desired effect.
If you have an older version, you should loop over the list and create a new PdfPTable for every 10 objects. Note that this is the better solution if you want to keep the memory use of your application low.