''
'' This code is part of Document Solutions for PDF .NET demos.
'' Copyright (c) MESCIUS inc. All rights reserved.
''
Imports System.IO
Imports System.Drawing
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.Structure
Imports GrapeCity.Documents.Pdf.MarkedContent
Imports 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 Function
End Class