Using the approach from post I was able to successfully create a text annotation for specific text. However I ran into a styling issue using this approach.
My dynamically generated HTML has a p tag with negative text-indent. The custom tag is a child of this p tag. Now the problem is the custom annot tag is inheriting the negative text-indent from it's parent which is making the content overlap with the preceding text. I tried to override the text-indent property by adding 0pt style for annot tag. It works fine when I open the HTML directly in the browser. But iText doesn't consider this style while generating the final output. Please see the sample below.
PDF Output:
HTML Code
<html>
<meta charset="utf-8">
<title>iText test</title>
<head>
<style type="text/css">
annot {
display: inline-block;
text-indent:0px !important;
}
</style>
</head>
<body>
<div>
<p style="margin-left:18pt; text-indent:-18pt; page-break-inside:avoid; page-break-after:avoid; line-height:120%"> The example of <annot> text markup </annot> annotation. </p>
</div>
</body>
</html>
Java Code:
public class C05E04_QRCode2 {
/**
* The path to the resulting PDF file.
*/
public static final String DEST = "C:\\dest.pdf";
/**
* The path to the source HTML file.
*/
public static final String SRC = "C:\\source.html";
/**
* The main method of this example.
*
* @param args no arguments are needed to run this example.
* @throws IOException signals that an I/O exception has occurred.
*/
public static void main(String[] args) throws IOException {
File file = new File(DEST);
file.getParentFile().mkdirs();
C05E04_QRCode2 app = new C05E04_QRCode2();
System.out.println("pdf");
app.createPdf(SRC, DEST);
}
/**
* Creates the PDF file.
*
* @param src the path to the source HTML file
* @param dest the path to the resulting PDF
* @throws IOException signals that an I/O exception has occurred.
*/
public void createPdf(String src, String dest) throws IOException {
ConverterProperties properties = new ConverterProperties().setTagWorkerFactory(new CustomTagWorkerFactory());
HtmlConverter.convertToPdf(new File(SRC), new File(DEST), properties);
}
private static class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
@Override
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if ("annot".equals(tag.name())) {
return new AnnotTagWorker(tag, context);
}
return super.getCustomTagWorker(tag, context);
}
}
private static class AnnotTagWorker extends PTagWorker {
public AnnotTagWorker(IElementNode element, ProcessorContext context) {
super(element, context);
}
@Override
public IPropertyContainer getElementResult() {
IPropertyContainer baseResult = super.getElementResult();
if (baseResult instanceof Paragraph) {
((Paragraph) baseResult).setNextRenderer(new AnnotTagRenderer((Paragraph) baseResult));
}
return baseResult;
}
}
private static class AnnotTagRenderer extends ParagraphRenderer {
public AnnotTagRenderer(Paragraph modelElement) {
super(modelElement);
}
@Override
public IRenderer getNextRenderer() {
return new AnnotTagRenderer((Paragraph) modelElement);
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
Rectangle occupiedArea = this.getOccupiedAreaBBox();
float[] quadPoints = new float[] {occupiedArea.getLeft(), occupiedArea.getTop(), occupiedArea.getRight(), occupiedArea.getTop(),
occupiedArea.getLeft(), occupiedArea.getBottom(), occupiedArea.getRight(), occupiedArea.getBottom()};
PdfAnnotation ann = PdfTextMarkupAnnotation.createHighLight(
new Rectangle(occupiedArea), quadPoints)
.setColor(ColorConstants.YELLOW)
.setTitle(new PdfString("Hello!"))
.setContents(new PdfString("I'm a popup."))
.setTitle(new PdfString("iText"));
drawContext.getDocument().getPage(this.getOccupiedArea().getPageNumber()).addAnnotation(ann);
}
}
}
By default the <annot>
tag would be ignored in terms of CSS properties processing, so your text-indent: 0px !important
declaration is essentially ignored. To enable CSS processing for custom tags, use a custom CSS applier factory:
private static class CustomCssApplierFactory extends DefaultCssApplierFactory {
@Override
public ICssApplier getCustomCssApplier(IElementNode tag) {
if ("annot".equals(tag.name())) {
return new BlockCssApplier();
}
return super.getCustomCssApplier(tag);
}
}
It's plugged into pdfHTML via ConverterProperties
as well:
ConverterProperties properties = new ConverterProperties()
.setTagWorkerFactory(new CustomTagWorkerFactory())
.setCssApplierFactory(new CustomCssApplierFactory());