jonathan
jonathan

Reputation: 67

How to convert some html elements into span elements and extract coordinates from them?

I am trying to convert some elements (labels) that my html contains into span and be able to extract the position (coordinates) from them. Could you please help me as I am new to iText 7:

My code is:

ConverterProperties properties = new ConverterProperties();
properties.SetTagWorkerFactory(new CustomTagWorker());

IList elements = HtmlConverter.ConvertToElements(html, properties);

foreach (IElement element in elements)
{
    document.Add((IBlockElement) element);
}

document.Close();

Custom tag workers:

private class CustomSpanTagWorker : iText.Html2pdf.Attach.Impl.Tags.SpanTagWorker
{
    public CustomSpanTagWorker(iText.StyledXmlParser.Node.IElementNode element, iText.Html2pdf.Attach.ProcessorContext context) : base(element, context)
    {
    }

    public override void ProcessEnd(iText.StyledXmlParser.Node.IElementNode element,iText.Html2pdf.Attach.ProcessorContext context)
    {
        base.ProcessEnd(element, context);
        string nombre = element.Name();
        IList elementResult = GetAllElements();

        if (elementResult != null )
        {
            foreach (iText.Layout.IPropertyContainer item in elementResult)
            {

                base.ProcessEnd(element, context);
            }

        }
    }
}

DefaultTagWorkerFactory:

if (tag.Name().Equals(iText.Html2pdf.Html.TagConstants.STRONG, StringComparison.OrdinalIgnoreCase))
{                        
    return new CustomSpanTagWorker(tag, context);
}

Upvotes: 0

Views: 636

Answers (1)

Alexey Subach
Alexey Subach

Reputation: 12302

In short, you need to pass the custom tag worker to the converter properties (already done in your code), then inspect the elements created by your custom tag worker, find Text element there and pass a custom renderer to that element. Renderer in turn will know all the details about the location of the text if you extend from the default implementation. Here is the code sample that prints the basic info about the resultant location:

String html = "hello <strong>world</strong> and others";
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.SetTagWorkerFactory(new CustomTagWorkerFactory());
HtmlConverter.ConvertToPdf(html, new ByteArrayOutputStream(), converterProperties);

The meaty helper classes:

private class CustomTagWorkerFactory : DefaultTagWorkerFactory {
    public override ITagWorker GetCustomTagWorker(IElementNode tag, ProcessorContext context) {
        if (tag.Name().Equals(iText.Html2pdf.Html.TagConstants.STRONG, StringComparison.InvariantCultureIgnoreCase)) {                        
            return new CustomSpanTagWorker(tag, context);
        }
        return base.GetCustomTagWorker(tag, context);
    }
}

private class CustomSpanTagWorker : SpanTagWorker {
    public CustomSpanTagWorker(IElementNode element, ProcessorContext context) : base(element, context) {
    }

    public override void ProcessEnd(IElementNode element, ProcessorContext context) {
        base.ProcessEnd(element, context);
        var leafElements= base.GetOwnLeafElements();
        if (leafElements.Count == 1 && leafElements[0] is Text) {
            (leafElements[0] as Text).SetNextRenderer(new CustomTextRenderer(leafElements[0] as Text));
        }
    }
}

private class CustomTextRenderer : TextRenderer {
    private Rectangle location;
    
    public CustomTextRenderer(Text textElement) : base(textElement) {
    }
    
    protected internal CustomTextRenderer(TextRenderer other) : base(other) {
    }

    public override IRenderer GetNextRenderer() {
        return new CustomTextRenderer((Text) modelElement);
    }
    
    protected override iText.Layout.Renderer.TextRenderer CreateCopy(GlyphLine gl, PdfFont font) {
        CustomTextRenderer copy = new CustomTextRenderer(this);
        copy.SetProcessedGlyphLineAndFont(gl, font);
        return copy;
    }

    public override void Draw(DrawContext drawContext) {
        base.Draw(drawContext);
        this.location = occupiedArea.GetBBox().Clone();
        Console.WriteLine(location);
    }

    public Rectangle GetLocation() {
        return location;
    }
}

Upvotes: 1

Related Questions