PdfUa2.vb
C# VB
'''' This code is part of Document Solutions for PDF .NET demos.'' Copyright (c) MESCIUS inc. All rights reserved.''Imports System.IOImports System.DrawingImports GrapeCity.Documents.PdfImports GrapeCity.Documents.Pdf.StructureImports GrapeCity.Documents.Pdf.MarkedContentImports GCTEXT = GrapeCity.Documents.Text
'' This sample shows how to create a PDF/UA-2 (accessible) compliant document.Public Class PdfUa2 Function CreatePDF(ByVal stream As Stream) As Integer Dim doc = New GcPdfDocument()
'' PDF/UA-2 is based on PDF 2.0: doc.PdfVersion = "2.0" '' The document language must be specified for PDF/UA: doc.Lang = "en" '' Mark the document as PDF/UA-2 conformant: doc.Metadata.PdfUa = 2 '' PDF/UA-2 requires the "revision" year of the ISO 14289-2:2024 standard itself (not the document's date): doc.Metadata.PdfUaRev = "2024" doc.Metadata.Title = "PDF/UA-2 compliant document" doc.ViewerPreferences.DisplayDocTitle = True '' Mark the document as conforming to Tagged PDF conventions (required for PDF/UA): doc.MarkInfo.Marked = True
Dim fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "NotoSans-Regular.ttf"))
'' PDF/UA-2 requires the structure tree to declare the namespaces it uses. '' Add the standard PDF 2.0 structure namespace: Dim ns = New [Namespace]("http://iso.org/pdf2/ssn") doc.StructTreeRoot.Namespaces.Add(ns)
'' PDF/UA-2 requires a "Document" structure element as the root of the structure tree, '' associated with the namespace declared above: Dim seDocument = New StructElement("Document") With {.NS = ns} doc.StructTreeRoot.Children.Add(seDocument)
Const chapterCount = 3 For i = 0 To chapterCount - 1 Dim page = doc.Pages.Add() Dim g = page.Graphics Dim headingTop = 72.0F
If i = 0 Then '' Structure Destinations are a very new PDF 2.0 mechanism - at the time of writing, '' neither the DsPdfViewer used in these demos, nor Adobe Acrobat, resolve them yet, '' so clicking a bookmark below may not navigate to its heading even though the '' destination itself is generated correctly (per the PDF/UA-2 and PDF 2.0 specs). '' This note is not part of the document's real content, so it is drawn using the '' already-embedded font (PDF/UA-2 requires every font used for rendering - including '' the standard 14 fonts - to be embedded) and marked as a layout artifact rather than '' tagged content (PDF/UA-2 requires all content to be either tagged or an artifact): Dim tlNote = g.CreateTextLayout() tlNote.DefaultFormat.Font = fnt tlNote.DefaultFormat.FontSize = 12 tlNote.MarginAll = 72 tlNote.MaxWidth = page.Size.Width tlNote.Append( "This document's outline (bookmarks) use PDF 2.0 ""Structure Destinations"" to point directly at each " & "chapter heading below, as required by PDF/UA-2. Neither the DsPdfViewer used in these demos, nor " & "Adobe Acrobat, currently resolve this new destination type, so clicking a bookmark may not navigate " & "to the target heading, even though the destination itself is generated correctly.") tlNote.PerformLayout(True)
Dim noteRect = tlNote.ContentRectangle noteRect.Inflate(9, 9)
g.BeginMarkedContent(New TagArtifact With {.Type = TagArtifact.Types.TypeLayout}) g.FillRectangle(noteRect, Color.FromArgb(213, 221, 240)) g.DrawRectangle(noteRect, Color.FromArgb(59, 92, 170), 0.5F) g.DrawTextLayout(tlNote, PointF.Empty) g.EndMarkedContent()
headingTop = noteRect.Bottom + 24 End If
'' Chapter heading, tagged as a top-level "H1" element under the Document root: Dim seHeading = New StructElement("H1") With {.DefaultPage = page} seDocument.Children.Add(seHeading)
Dim tlHeading = g.CreateTextLayout() tlHeading.MarginAll = 72 tlHeading.MarginTop = headingTop tlHeading.MaxWidth = page.Size.Width tlHeading.DefaultFormat.Font = fnt tlHeading.DefaultFormat.FontBold = True tlHeading.DefaultFormat.FontSize = 20 tlHeading.Append($"Chapter {i + 1}")
g.BeginMarkedContent(New TagMcid("H1", 0)) g.DrawTextLayout(tlHeading, PointF.Empty) g.EndMarkedContent() seHeading.ContentItems.Add(New McidContentItemLink(0))
'' Chapter body, tagged as a "P" element under the same Document root: Dim seParagraph = New StructElement("P") With {.DefaultPage = page} seDocument.Children.Add(seParagraph)
Dim tlBody = g.CreateTextLayout() tlBody.MarginAll = 72 tlBody.MarginTop = tlHeading.ContentRectangle.Bottom + 24 tlBody.MaxWidth = page.Size.Width tlBody.DefaultFormat.Font = fnt tlBody.DefaultFormat.FontSize = 12 tlBody.Append(Util.LoremIpsum(3, 2, 5))
g.BeginMarkedContent(New TagMcid("P", 1)) g.DrawTextLayout(tlBody, PointF.Empty) g.EndMarkedContent() seParagraph.ContentItems.Add(New McidContentItemLink(1))
'' Add an outline entry for this chapter using a "Structure Destination" - one that points '' at the heading's structure element rather than a page/coordinate pair, as required by '' PDF/UA-2 (see PDF 2.0 spec, 12.3.2.3 "Structure Destinations"): doc.Outlines.Add(New OutlineNode($"Chapter {i + 1}", New DestinationFitBV(seHeading, Nothing))) Next
doc.Save(stream) Return doc.Pages.Count End FunctionEnd Class