//// This code is part of Document Solutions for PDF .NET demos.// Copyright (c) MESCIUS inc. All rights reserved.//usingSystem.IO;usingSystem.Drawing;usingGrapeCity.Documents.Pdf;usingGrapeCity.Documents.Pdf.Structure;usingGrapeCity.Documents.Pdf.MarkedContent;usingGCTEXT = GrapeCity.Documents.Text; namespaceDsPdfWeb.Demos.Basics{// This sample shows how to create a PDF/UA-2 (accessible) compliant document.publicclassPdfUa2 {publicintCreatePDF(Stream stream) {var doc = newGcPdfDocument(); // 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; var 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:var ns = newNamespace("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:var seDocument = newStructElement("Document") { NS = ns }; doc.StructTreeRoot.Children.Add(seDocument); constintchapterCount = 3;for (int i = 0; i < chapterCount; ++i) {var page = doc.Pages.Add();var g = page.Graphics;float headingTop = 72; if (i == 0) {// 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):var 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); var noteRect = tlNote.ContentRectangle; noteRect.Inflate(9, 9); g.BeginMarkedContent(newTagArtifact { 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; } // Chapter heading, tagged as a top-level "H1" element under the Document root:var seHeading = newStructElement("H1") { DefaultPage = page }; seDocument.Children.Add(seHeading); var 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(newTagMcid("H1", 0)); g.DrawTextLayout(tlHeading, PointF.Empty); g.EndMarkedContent(); seHeading.ContentItems.Add(newMcidContentItemLink(0)); // Chapter body, tagged as a "P" element under the same Document root:var seParagraph = newStructElement("P") { DefaultPage = page }; seDocument.Children.Add(seParagraph); var 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(Common.Util.LoremIpsum(3, 2, 5)); g.BeginMarkedContent(newTagMcid("P", 1)); g.DrawTextLayout(tlBody, PointF.Empty); g.EndMarkedContent(); seParagraph.ContentItems.Add(newMcidContentItemLink(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(newOutlineNode($"Chapter {i + 1}", newDestinationFitBV(seHeading, null))); } doc.Save(stream);return doc.Pages.Count; } }}