//// This code is part of Document Solutions for PDF .NET demos.// Copyright (c) MESCIUS inc. All rights reserved.//usingSystem;usingSystem.IO;usingSystem.Drawing;usingGrapeCity.Documents.Pdf;usingGrapeCity.Documents.Text;usingGrapeCity.Documents.Pdf.Structure;usingGrapeCity.Documents.Pdf.MarkedContent; namespaceDsPdfWeb.Demos.Basics{// This sample shows how to create tagged (structured) PDF and attach// tags to individual paragraphs in a TextLayout that is used to render// them together, splitting between pages. // The code generating the document is similar to that used in PaginatedText,// but adds tags.// To see/explore the tags, open the document in Adobe Acrobat Pro and go to// View | Navigation Panels | Tags.publicclassTagTextLayout {publicintCreatePDF(Stream stream) {var doc = newGcPdfDocument(); // Create a Part element, it will contain P (paragraph) elements:var sePart = newStructElement("Part"); doc.StructTreeRoot.Children.Add(sePart); // Create and set up a TextLayout to render paragraphs:var tl = newTextLayout(72); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; tl.FirstLineIndent = 72 / 2; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; tl.MarginAll = tl.Resolution;//// Append the text (20 paragraphs so they would not fit on a single page)// (note that TextLayout interprets "\r\n" as paragraph delimiter)://// Get the text (20 paragraphs):var text = Common.Util.LoremIpsum(20);// In order to tag the individual paragraphs, we need to split the text into paragraphs,// and use each paragraph format's Tag property (which is not related to PDF tags, // it is just an arbitrary data that can be associated with a TextFormat) to add the// paragraph's index to the paragraph:var pars = text.Split(newchar[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);for (int i = 0; i < pars.Length; ++i) {var tf = newTextFormat(tl.DefaultFormat) { Tag = i }; tl.AppendLine(pars[i], tf); } // Layout the text: tl.PerformLayout(true);// Use split options to provide widow/orphan control:var to = newTextSplitOptions(tl) {MinLinesInFirstParagraph = 2,MinLinesInLastParagraph = 2, };// TextLayoutHandler implements ITextLayoutHandler, which// allows tagging the text as it is rendered:var tlh = newTextLayoutHandler() { ParentElement = sePart }; // In a loop, split and render the text:while (true) {// 'rest' will accept the text that did not fit:var splitResult = tl.Split(to, outTextLayout rest);var page = doc.Pages.Add();var g = page.Graphics;// Tell the TextLayoutHandler which page we're on: tlh.Page = page;// ..and associate it with the graphics: g.TextLayoutHandler = tlh;// Draw the text that fits on the current page, and advance to next page unless we're done: g.DrawTextLayout(tl, PointF.Empty);if (splitResult != SplitResult.Split)break; tl = rest; }// Mark document as tagged: doc.MarkInfo.Marked = true; // Done: doc.Save(stream);return doc.Pages.Count; } // Custom class that allows tagging content as it is rendered by TextLayout:privateclassTextLayoutHandler : ITextLayoutHandler {privateint_tagIndex;privateint_currentParagraphIndex = -1;privateStructElement_currentparagraphElement;publicStructElementParentElement;publicPagePage; publicvoidTextTagBegin(GcPdfGraphics graphics, TextLayout textLayout, object tag) {int paragraphIndex;if (tag isint) paragraphIndex = (int)tag;else paragraphIndex = -1; StructElement paragraphElement;if (_currentParagraphIndex == paragraphIndex) { paragraphElement = _currentparagraphElement; }else {if (paragraphIndex >= 0) { paragraphElement = newStructElement("P");ParentElement.Children.Add(paragraphElement);_currentparagraphElement = paragraphElement;_currentParagraphIndex = paragraphIndex; }else { paragraphElement = null;_currentparagraphElement = paragraphElement;_currentParagraphIndex = paragraphIndex; } } //if (paragraphElement != null) { graphics.BeginMarkedContent(newTagMcid("P", _tagIndex));var mcil = newMcrContentItemLink(); mcil.MCID = _tagIndex; mcil.Page = Page; paragraphElement.ContentItems.Add(mcil);_tagIndex++; } } publicvoidTextTagEnd(GcPdfGraphics graphics, TextLayout textLayout, object tag) {if (_currentparagraphElement != null) graphics.EndMarkedContent(); } publicvoidAddTextArea(RectangleF bounds) { } } }}