TagTextLayout.vb
 '' '' This code is part of Document Solutions for PDF demos. '' Copyright (c) MESCIUS inc. All rights reserved. '' Imports System.IO Imports System.Drawing Imports GrapeCity.Documents.Pdf Imports GrapeCity.Documents.Text Imports GrapeCity.Documents.Drawing Imports GrapeCity.Documents.Pdf.Structure Imports GrapeCity.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. Public Class TagTextLayout Function CreatePDF(ByVal stream As Stream) As Integer Dim doc = New GcPdfDocument() '' Create a Part element, it will contain P (paragraph) elements: Dim sePart = New StructElement("Part") doc.StructTreeRoot.Children.Add(sePart) '' Create and set up a TextLayout to render paragraphs: Dim tl = New TextLayout(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(New Char() {vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries) For i = 0 To pars.Length - 1 Dim tf = New TextFormat(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 = New TextSplitOptions(tl) With { .MinLinesInFirstParagraph = 2, .MinLinesInLastParagraph = 2 } '' TextLayoutHandler implements ITextLayoutHandler, which '' allows tagging the text as it is rendered: Dim tlh = New TextLayoutHandler() With {.ParentElement = sePart} '' In a loop, split and render the text: While True '' 'rest' will accept the text that did not fit: Dim rest As TextLayout = Nothing Dim 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.Split Then Exit While End If tl = rest End While '' Mark document as tagged: doc.MarkInfo.Marked = True '' '' Done: doc.Save(stream) Return doc.Pages.Count End Function '' Custom class that allows tagging content as it is rendered by TextLayout: Private Class TextLayoutHandler : Implements ITextLayoutHandler Private _tagIndex As Integer Private _currentParagraphIndex As Integer = -1 Private _currentparagraphElement As StructElement Public Property ParentElement As StructElement Public Property Page As Page Public Sub TextTagBegin(ByVal graphics As GcPdfGraphics, ByVal textLayout As TextLayout, ByVal tag As Object) Implements ITextLayoutHandler.TextTagBegin Dim paragraphIndex As Integer If TypeOf tag Is Integer Then paragraphIndex = CInt(tag) Else paragraphIndex = -1 End If Dim paragraphElement As StructElement If _currentParagraphIndex = paragraphIndex Then paragraphElement = _currentparagraphElement Else paragraphElement = New StructElement("P") ParentElement.Children.Add(paragraphElement) _currentparagraphElement = paragraphElement _currentParagraphIndex = paragraphIndex End If '' graphics.BeginMarkedContent(New TagMcid("P", _tagIndex)) Dim mcil = New McrContentItemLink() mcil.MCID = _tagIndex mcil.Page = Page paragraphElement.ContentItems.Add(mcil) _tagIndex += 1 End Sub Public Sub TextTagEnd(ByVal graphics As GcPdfGraphics, ByVal textLayout As TextLayout, ByVal tag As Object) Implements ITextLayoutHandler.TextTagEnd graphics.EndMarkedContent() End Sub Public Sub AddTextArea(ByVal bounds As RectangleF) Implements ITextLayoutHandler.AddTextArea End Sub End Class End Class