I'm trying to use itext7 to a paragraph to the top of an existing pdf that is and must remain wcag compliant. The new paragraph must also be the first element in the logical structure to preserve the natural reading order.
The following iText7 8.0 c# code almost does the job:
using var pdfReader = new PdfReader("wcag-compliant.pdf");
pdfReader.SetUnethicalReading(true);
var outputPath = "new-wcag-compliant.pdf";
using var writer = new PdfWriter(new FileStream(outputPath, FileMode.Create)).SetSmartMode(true);
using var pdfDocument = new PdfADocument(pdfReader, writer);
using var document = new iText.Layout.Document(pdfDocument);
var font = PdfFontFactory.CreateFont(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "Arial.ttf"), PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
var pageSize = pdfDocument.GetPage(1).GetPageSize();
var p = new Paragraph().SetFixedPosition(65, pageSize.GetHeight() - 80, 200);
var text = new Text("Text of new paragraph");
p.Add(text).SetFont(font);
p.GetAccessibilityProperties().SetAlternateDescription("Description of new paragraph");
pdfDocument.GetTagStructureContext().GetAutoTaggingPointer().AddTag(0, p.GetAccessibilityProperties());
document.Add(p);
document.Close();
Unfortunately, the new paragraph gets wrapped in another paragraph in the tagging structure which is a violation of WCAG as shown here with the PAC tool:
What is the correct way to add new text to an existing WCAG compliant PDF and at the same time placing that text in the logical structure in a suitable place?
I haven't been able to find a solution using the higher-level API with Paragraph ect., but with inspiration from another answer I found a more low-level solution using PdfCanvas:
using var pdfReader = new PdfReader("wcag-compliant.pdf");
pdfReader.SetUnethicalReading(true);
var outputPath = "new-wcag-compliant.pdf";
using var writer = new PdfWriter(new FileStream(outputPath, FileMode.Create)).SetSmartMode(true);
using var pdfDocument = new PdfADocument(pdfReader, writer);
using var document = new iText.Layout.Document(pdfDocument);
var font = PdfFontFactory.CreateFont(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "Arial.ttf"), PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
var firstPage = pdfDocument.GetPage(1);
var canvas = new PdfCanvas(firstPage);
var ttp = new TagTreePointer(pdfDocument);
ttp.SetPageForTagging(firstPage);
ttp.AddTag(0, StandardRoles.P);
canvas.BeginText()
.SetFontAndSize(font, 8)
.OpenTag(ttp.GetTagReference())
.MoveText(65, firstPage.GetPageSize().GetTop() - 80)
.ShowText(text)
.CloseTag()
.EndText();
document.Close();
This code adds the new text in a new paragraph which is placed as the first element of the logical structure.