Reputation: 13
I'm trying to generate PDF reports using iTextSharp with customer information, header and footer etc. All these reports are already generated using EVO APIs. As part of a migration process, we are planning to generate these reports using iTextSharp APIs.
I need to know if there is any possibility to provide a ready to render HTML string to iTextSharp PDF header (Existing EVO design accepts HTML string and build PDF), instead of using PageEvents to design with PDFPTable and PDFPCell (as the number of reports are huge and to avoid rework)
Upvotes: 1
Views: 7442
Reputation: 95918
I need to know if there is any possibility to provide a ready to render HTML string to iTextSharp PDF header (Existing EVO design accepts HTML string and build PDF), instead of using PageEvents to design with PDFPTable and PDFPCell
You will have to use page events to draw header or footers but there is no need to use PdfPTable
explicitly there. You actually can render html during a page event, e.g. like this:
[Test]
public void CreatePdfWithHtmlHeader()
{
string htmlHeader = "<!DOCTYPE html><html><body><table style=\"width: 100%; border: 1px solid black;\"><tr><td>A</td><td>B</td></tr></table></body></html>";
using (FileStream output = new FileStream(@"C:\Temp\test-results\content\html-header.pdf", FileMode.Create, FileAccess.Write))
using (Document document = new Document(PageSize.A4))
{
PdfWriter writer = PdfWriter.GetInstance(document, output);
writer.PageEvent = new HtmlPageEventHelper(htmlHeader);
document.Open();
document.Add(new Paragraph("1"));
document.NewPage();
document.Add(new Paragraph("2"));
}
}
making use the following two small helper classes.
HtmlPageEventHelper
is a page event listener drawing a given html sniplet into the page header. Obviously it can alternatively or additionally write into the page footer, simply use appropriate column coordinates
public class HtmlPageEventHelper : PdfPageEventHelper
{
public HtmlPageEventHelper(string html)
{
this.html = html;
}
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
ColumnText ct = new ColumnText(writer.DirectContent);
XMLWorkerHelper.GetInstance().ParseXHtml(new ColumnTextElementHandler(ct), new StringReader(html));
ct.SetSimpleColumn(document.Left, document.Top, document.Right, document.GetTop(-20), 10, Element.ALIGN_MIDDLE);
ct.Go();
}
string html = null;
}
For more complex HTML sniplets you may want to replace the XMLWorkerHelper.GetInstance().ParseXHtml
call by a customized parser call as presented in @Skary's answer.
ColumnTextElementHandler
is an IElementHandler
implementation that adds content (generated e.g. by parsing HTML) to a ColumnText
public class ColumnTextElementHandler : IElementHandler
{
public ColumnTextElementHandler(ColumnText ct)
{
this.ct = ct;
}
ColumnText ct = null;
public void Add(IWritable w)
{
if (w is WritableElement)
{
foreach (IElement e in ((WritableElement)w).Elements())
{
ct.AddElement(e);
}
}
}
}
By the way, the test above produces a PDF with this content:
...
...
Disclaimer: I predominantly work with Java and have not used the XmlWorker
before. Thus, this code may have considerable potential for improvement.
Upvotes: 5
Reputation: 1362
I am not sure to have understand you question right.
If you are asking how to parse HTML to PDF using iTextSharp here is the solutin i found time ago :
using (Document document = new Document(size))
{
var writer = PdfWriter.GetInstance(document, stream);
document.Open();
document.NewPage();
document.Add(new Chunk(""));
var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
tagProcessors.RemoveProcessor(HTML.Tag.IMG);
tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor());
var charset = Encoding.UTF8;
CssFilesImpl cssFiles = new CssFilesImpl();
cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
var cssResolver = new StyleAttrCSSResolver(cssFiles);
cssResolver.AddCss(srcCssData, "utf-8", true);
var hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
hpc.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors);
var htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, writer));
var pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(pipeline, true);
var xmlParser = new XMLParser(true, worker, charset);
xmlParser.Parse(new StringReader(srcFileData));
document.Close();
}
To get it work you need to add custom image processor to inline image in the HTML you provide to tha above converte function :
public class CustomImageTagProcessor : iTextSharp.tool.xml.html.Image
{
public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
{
IDictionary<string, string> attributes = tag.Attributes;
string src;
if (!attributes.TryGetValue(HTML.Attribute.SRC, out src))
return new List<IElement>(1);
if (string.IsNullOrEmpty(src))
return new List<IElement>(1);
if (src.StartsWith("data:image/", StringComparison.InvariantCultureIgnoreCase))
{
// data:[<MIME-type>][;charset=<encoding>][;base64],<data>
var base64Data = src.Substring(src.IndexOf(",") + 1);
var imagedata = Convert.FromBase64String(base64Data);
var image = iTextSharp.text.Image.GetInstance(imagedata);
var list = new List<IElement>();
var htmlPipelineContext = GetHtmlPipelineContext(ctx);
list.Add(GetCssAppliers().Apply(new Chunk((iTextSharp.text.Image)GetCssAppliers().Apply(image, tag, htmlPipelineContext), 0, 0, true), tag, htmlPipelineContext));
return list;
}
else
{
return base.End(ctx, tag, currentContent);
}
}
}
Upvotes: 2