I am a .NET developer, so the code is in C #. But you should be able to easily translate the following.
iText is a PDF library, and the [X]HTML quite complex, so it is not fully functional in this regard. Whenever parsing [X]HTML and everything is not as you expect from certain tags, the basic steps that you must follow are as follows:
- Verify
XML Worker supports tag: tag class . - If the tag is supported, which is true in this case, take a look at the default implementation. Here it is handled by the HorizontalRule class . However, we do not see support for your use case, so one way is to use this code as a plan. (below). You can also inherit from a specific tag class and override the End () method as done here . In any case, all you do is implement a special tag processor.
- If the tag is not supported, you need to collapse your own tag processor, inheriting from AbstractTagProcessor .
Anyway, here is a simple example to get you started. First, a custom tag processor:
public class CustomHorizontalRule : AbstractTagProcessor { public override IList<IElement> Start(IWorkerContext ctx, Tag tag) { IList<IElement> result; LineSeparator lineSeparator; var cssUtil = CssUtils.GetInstance(); try { IList<IElement> list = new List<IElement>(); HtmlPipelineContext htmlPipelineContext = this.GetHtmlPipelineContext(ctx); Paragraph paragraph = new Paragraph(); IDictionary<string, string> css = tag.CSS; float baseValue = 12f; if (css.ContainsKey("font-size")) { baseValue = cssUtil.ParsePxInCmMmPcToPt(css["font-size"]); } string text; css.TryGetValue("margin-top", out text); if (text == null) text = "0.5em"; string text2; css.TryGetValue("margin-bottom", out text2); if (text2 == null) text2 = "0.5em"; string border; css.TryGetValue(CSS.Property.BORDER_BOTTOM_STYLE, out border); lineSeparator = border != null && border == "dotted" ? new DottedLineSeparator() : new LineSeparator(); var element = (LineSeparator)this.GetCssAppliers().Apply( lineSeparator, tag, htmlPipelineContext ); string color; css.TryGetValue(CSS.Property.BORDER_BOTTOM_COLOR, out color); if (color != null) { // WebColors deprecated, but docs don't state replacement element.LineColor = WebColors.GetRGBColor(color); } paragraph.SpacingBefore += cssUtil.ParseValueToPt(text, baseValue); paragraph.SpacingAfter += cssUtil.ParseValueToPt(text2, baseValue); paragraph.Leading = 0f; paragraph.Add(element); list.Add(paragraph); result = list; } catch (NoCustomContextException cause) { throw new RuntimeWorkerException( LocaleMessages.GetInstance().GetMessage("customcontext.404"), cause ); } return result; } }
Most of the code is taken directly from an existing source, with the exception of checks for CSS.Property.BORDER_BOTTOM_STYLE and CSS.Property.BORDER_BOTTOM_COLOR to set the style and color of the frame if they are included in the <hr> style attribute.
Then you add the custom tag handler above to the XML Worker TagProcessorFactory :
using (var stream = new FileStream(OUTPUT_FILE, FileMode.Create)) { using (var document = new Document()) { var writer = PdfWriter.GetInstance(document, stream); document.Open(); var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory(); // custom tag processor above tagProcessorFactory.AddProcessor( new CustomHorizontalRule(), new string[] { HTML.Tag.HR } ); var htmlPipelineContext = new HtmlPipelineContext(null); htmlPipelineContext.SetTagFactory(tagProcessorFactory); var pdfWriterPipeline = new PdfWriterPipeline(document, writer); var htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline); var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true); var cssResolverPipeline = new CssResolverPipeline( cssResolver, htmlPipeline ); var worker = new XMLWorker(cssResolverPipeline, true); var parser = new XMLParser(worker); var xHtml = "<hr style='border:1px dotted red' />"; using (var stringReader = new StringReader(xHtml)) { parser.Parse(stringReader); } } }
It should be noted that even if we use the abbreviated border inline style, the iText CSS parser typically sets the style to all . Ie, you can use any of the four handmade styles for validation - I just used CSS.Property.BORDER_BOTTOM_STYLE and CSS.Property.BORDER_BOTTOM_COLOR .
Received PDF:
