TagTextLayout.vb
'' 完毕:
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

'' 此示例展示了如何创建带标签(结构化)的 PDF 并附加
'' 用于渲染的 TextLayout 中各个段落的标签
'' 它们放在一起,在页面之间分开。
'' 生成文档的代码与PaginatedText中使用的代码类似,
'' 但添加了标签。
'' 要查看/探索标签,请在 Adob​​e Acrobat Pro 中打开文档并转到
'' 查看 |导航面板|标签。
Public Class TagTextLayout
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()

        '' 创建一个 Part 元素,它将包含 P(段落)元素:
        Dim sePart = New StructElement("Part")
        doc.StructTreeRoot.Children.Add(sePart)

        '' 创建并设置 TextLayout 来呈现段落:
        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
        '' 附加文本(20 段,这样一页就放不下)
        '' (请注意,TextLayout 将“\r\n”解释为段落分隔符):
        '' 
        '' 获取文本(20段):
        Dim text = Util.LoremIpsum(20)
        '' 为了标记各个段落,我们需要将文本拆分为段落,
        '' 并使用每个段落格式的 Tag 属性(与 PDF 标签无关,
        '' 它只是可以与 TextFormat 关联的任意数据)以添加
        '' 段落的索引:
        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

        '' 布局文本:
        tl.PerformLayout(True)
        '' 使用分割选项来提供寡妇/孤儿控制:
        Dim tso = New TextSplitOptions(tl) With {
            .MinLinesInFirstParagraph = 2,
            .MinLinesInLastParagraph = 2
        }
        '' TextLayoutHandler 实现了 ITextLayoutHandler,它
        '' 允许在呈现文本时对其进行标记:
        Dim tlh = New TextLayoutHandler() With {.ParentElement = sePart}

        '' 在循环中,分割并渲染文本:
        While True
            '' 'rest' 将接受不适合的文本:
            Dim rest As TextLayout = Nothing
            Dim splitResult = tl.Split(tso, rest)
            Dim page = doc.Pages.Add()
            Dim g = page.Graphics
            '' 告诉 TextLayoutHandler 我们在哪个页面:
            tlh.Page = page
            '' ..并将其与图形相关联:
            g.TextLayoutHandler = tlh
            '' 绘制适合当前页面的文本,然后前进到下一页,除非我们完成:
            g.DrawTextLayout(tl, PointF.Empty)
            If splitResult <> SplitResult.Split Then
                Exit While
            End If
            tl = rest
        End While
        '' 将文档标记为已标记:
        doc.MarkInfo.Marked = True
        ''
        '' 完毕:
        doc.Save(stream)
        Return doc.Pages.Count
    End Function

    '' 允许在 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