'''' This code is part of Document Solutions for PDF .NET demos.'' Copyright (c) MESCIUS inc. All rights reserved.''ImportsSystem.IOImportsSystem.DrawingImportsGrapeCity.Documents.PdfImportsGrapeCity.Documents.TextImportsGrapeCity.Documents.Pdf.StructureImportsGrapeCity.Documents.Pdf.MarkedContent '' 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.PublicClassTagTextLayoutFunctionCreatePDF(ByVal stream AsStream) AsIntegerDim doc = NewGcPdfDocument() '' Create a Part element, it will contain P (paragraph) elements:Dim sePart = NewStructElement("Part") doc.StructTreeRoot.Children.Add(sePart) '' Create and set up a TextLayout to render paragraphs:Dim 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 vbCrLf as paragraph delimiter):'''' Get the text (20 paragraphs):Dim text = 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:Dim pars = text.Split(NewChar() {vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries)For i = 0To pars.Length - 1Dim tf = NewTextFormat(tl.DefaultFormat) With {.Tag = i} tl.AppendLine(pars(i), tf)Next '' Layout the text: tl.PerformLayout(True)'' Use split options to provide widow/orphan control:Dim tso = NewTextSplitOptions(tl) With { .MinLinesInFirstParagraph = 2, .MinLinesInLastParagraph = 2 }'' TextLayoutHandler implements ITextLayoutHandler, which'' allows tagging the text as it is rendered:Dim tlh = NewTextLayoutHandler() With {.ParentElement = sePart} '' In a loop, split and render the text:WhileTrue'' 'rest' will accept the text that did not fit:Dim rest AsTextLayout = NothingDim splitResult = tl.Split(tso, rest)Dim page = doc.Pages.Add()Dim 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.SplitThenExitWhileEndIf tl = restEndWhile'' Mark document as tagged: doc.MarkInfo.Marked = True'''' Done: doc.Save(stream)Return doc.Pages.CountEndFunction '' Custom class that allows tagging content as it is rendered by TextLayout:PrivateClassTextLayoutHandler : ImplementsITextLayoutHandlerPrivate_tagIndexAsIntegerPrivate_currentParagraphIndexAsInteger = -1Private_currentparagraphElementAsStructElementPublicPropertyParentElementAsStructElementPublicPropertyPageAsPage PublicSubTextTagBegin(ByVal graphics AsGcPdfGraphics, ByVal textLayout AsTextLayout, ByVal tag AsObject) ImplementsITextLayoutHandler.TextTagBeginDim paragraphIndex AsIntegerIfTypeOf tag IsIntegerThen paragraphIndex = CInt(tag)Else paragraphIndex = -1EndIf Dim paragraphElement AsStructElementIf_currentParagraphIndex = paragraphIndex Then paragraphElement = _currentparagraphElementElse paragraphElement = NewStructElement("P")ParentElement.Children.Add(paragraphElement)_currentparagraphElement = paragraphElement_currentParagraphIndex = paragraphIndexEndIf'' graphics.BeginMarkedContent(NewTagMcid("P", _tagIndex))Dim mcil = NewMcrContentItemLink() mcil.MCID = _tagIndex mcil.Page = Page paragraphElement.ContentItems.Add(mcil)_tagIndex += 1EndSub PublicSubTextTagEnd(ByVal graphics AsGcPdfGraphics, ByVal textLayout AsTextLayout, ByVal tag AsObject) ImplementsITextLayoutHandler.TextTagEnd graphics.EndMarkedContent()EndSub PublicSubAddTextArea(ByVal bounds AsRectangleF) ImplementsITextLayoutHandler.AddTextAreaEndSubEndClassEndClass