pdfHTML: Creation and/or merging of outlines for documents
With pdfHTML 3.0.0 (released with iText Core 7.1.11) we improved the creation and/or merging of document outlines.
Details
- When we generate a PDF file from iText that contains outlines, clicking such outlines should redirect to the corresponding contents.
- It works fine in most cases but when we merge multiple PDFs where all the documents contain, some of the links redirect to the wrong content.
- We need to implement an outline handler in such a way that it allows us to change the destination prefix name so that the PdfMerger can resolve the collisions.
- Prior to version 7.1.11, this could not be done at all; each destination name had one prefix, and this created problems when merging two documents created by pdfHTML, because destination names in different documents had the same prefix, leading to merge conflicts.
The following example creates a custom outline handler to resolve this issue:
JAVA
JAVA
package com.itext.mergeoutliner;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.attach.impl.OutlineHandler;
import com.itextpdf.styledxmlparser.node.IElementNode;
public class MergeOutliner {
public void manipulatePdf(String htmlSource, String pdfDest, String resourceLoc) throws IOException {
try {
// Base URI is required to resolve the path to source files
ConverterProperties converterProperties = new ConverterProperties().setBaseUri(resourceLoc);
// Create custom outline handler
Map<String, Integer> priorityMappings = new HashMap<String, Integer>();
priorityMappings.put("p", 1);
priorityMappings.put("h1", 2);
OutlineHandler customOutlineHandler = new CustomOutlineHandler().putAllTagPriorityMappings(priorityMappings);
customOutlineHandler.setDestinationNamePrefix("custom-prefix-");
converterProperties.setOutlineHandler(customOutlineHandler);
HtmlConverter.convertToPdf(new FileInputStream(htmlSource), new FileOutputStream(pdfDest), converterProperties);
}
catch(IOException e) {
e.getMessage();
}
}
public class CustomOutlineHandler extends OutlineHandler {
@Override
protected String generateUniqueDestinationName(IElementNode element) {
String destinationName = super.generateUniqueDestinationName(element);
if ("p".equals(element.name())) {
destinationName = destinationName.replace(getDestinationNamePrefix(), "paragraph-prefix-");
}
return destinationName;
}
}
}
C#
C#
using iText.Html2pdf;
using iText.Html2pdf.Attach.Impl;
using iText.StyledXmlParser.Node;
using System.Collections.Generic;
using System.IO;
namespace MergeOutliner
{
class MergeOutliner
{
public void manipulatePdf(string htmlSource, string pdfDest, string resourceLoc)
{
// Base URI is required to resolve the path to source files
ConverterProperties converterProperties = new ConverterProperties().SetBaseUri(resourceLoc);
using (var htmlStream = File.OpenRead(htmlSource))
{
if (File.Exists(pdfDest))
{
File.Delete(pdfDest);
}
using (var pdfStream = File.OpenWrite(pdfDest))
{
IDictionary<string, int?> priorityMappings = new Dictionary<string, int?>();
priorityMappings.Add("p", 1);
priorityMappings.Add("h1", 2);
OutlineHandler customOutlineHandler = new CustomOutlineHandler().PutAllTagPriorityMappings(priorityMappings);
customOutlineHandler.SetDestinationNamePrefix("custom-prefix-");
converterProperties.SetOutlineHandler(customOutlineHandler);
HtmlConverter.ConvertToPdf(htmlStream, pdfStream, converterProperties);
}
}
// Create custom outline handler
}
public class CustomOutlineHandler : OutlineHandler
{
protected override string GenerateUniqueDestinationName(IElementNode element)
{
string destinationName = base.GenerateUniqueDestinationName(element);
if ("p".Equals(element.Name()))
{
destinationName = destinationName.Replace(GetDestinationNamePrefix(), "paragraph-prefix-");
}
return destinationName;
}
}
}
}