BalancedColumns.vb
'' 完毕:
Imports System.IO
Imports System.Drawing
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text

'' 创建具有平衡列的多列文本布局。
'' 此示例的核心是 TextLayout.SplitAndBalance() 方法
'' 它允许在多列之间拆分文本,
'' 并平衡这些柱子,使它们的高度相似,
'' 从而使您能够制作类似杂志和报纸的文本布局。
Public Class BalancedColumns
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim font = StandardFonts.Times
        Dim fontSize = 12
        '' 周围 1/2" 边距(72 dpi 是 GcDocs.Pdf 使用的默认分辨率):
        Dim margin = 72 / 2
        Dim pageWidth = doc.PageSize.Width
        Dim pageHeight = doc.PageSize.Height
        Dim cW = pageWidth - margin * 2
        '' 章节标题的文本格式:
        Dim tlCaption = New TextLayout(72)
        tlCaption.DefaultFormat.Font = font
        tlCaption.DefaultFormat.FontSize = fontSize + 4
        tlCaption.DefaultFormat.Underline = True
        tlCaption.MaxWidth = pageWidth
        tlCaption.MaxHeight = pageHeight
        tlCaption.MarginLeft = margin
        tlCaption.MarginTop = margin
        tlCaption.MarginRight = margin
        tlCaption.MarginBottom = margin
        tlCaption.TextAlignment = TextAlignment.Center
        '' 章节标题的高度(为简单起见,使用常量):
        Const captionH = 24.0F
        '' 主文档正文的文本布局(默认 GcDocs.Pdf 分辨率为 72dpi):
        Dim tl = New TextLayout(72)
        tl.DefaultFormat.Font = font
        tl.DefaultFormat.FontSize = fontSize
        tl.FirstLineIndent = 72 / 2
        tl.MaxWidth = pageWidth
        tl.MaxHeight = pageHeight
        tl.MarginLeft = margin
        tl.MarginRight = margin
        tl.MarginBottom = margin
        tl.MarginTop = margin + captionH
        tl.ColumnWidth = cW * 0.3F
        tl.TextAlignment = TextAlignment.Justified
        '' 控制附加列的 PageSplitArea 数组(第一列由
        '' “主”TextLayout,对于每个附加的 TextLayout,必须提供一个 PageSplitArea -
        '' 它将创建并返回一个 TextLayout,然后可用于呈现该列):
        Dim psas As PageSplitArea() = {
            New PageSplitArea(tl) With {.MarginLeft = tl.MarginLeft + (cW * 0.35F)},
            New PageSplitArea(tl) With {.ColumnWidth = -cW * 0.3F}
        }
        '' 用于控制页面之间拆分文本的拆分选项:
        Dim tso = New TextSplitOptions(tl) With {
            .RestMarginTop = margin,
            .MinLinesInFirstParagraph = 2,
            .MinLinesInLastParagraph = 2
        }
        '' 生成多个“章节”,为每个章节提供大纲条目:
        Const NChapters = 20
        doc.Pages.Add()
        For i = 1 To NChapters
            '' 打印所有列的章节标题:
            Dim chapter = $"Chapter {i}"
            tlCaption.Clear()
            tlCaption.Append(chapter)
            tlCaption.PerformLayout(True)
            doc.Pages.Last.Graphics.DrawTextLayout(tlCaption, PointF.Empty)
            '' 为章节添加大纲节点:
            doc.Outlines.Add(New OutlineNode(chapter, New DestinationFitV(doc.Pages.Last, Nothing)))
            ''
            '' 清除上一章的文本并添加新的章节:
            tl.FirstLineIsStartOfParagraph = True
            tl.LastLineIsEndOfParagraph = True
            tl.Clear()
            tl.Append(Util.LoremIpsum(5, 7, 9, 15, 25))
            tl.PerformLayout(True)
            '' 用于保存最后一章结尾底部坐标的变量:
            Dim contentBottom = 0F
            '' 打印章节:
            Dim tls = New TextLayoutSplitter(tl)
            While (True)
                Dim tlCol0 = tls.SplitAndBalance(psas, tso)
                Dim g = doc.Pages.Last.Graphics
                g.DrawTextLayout(tlCol0, PointF.Empty)
                g.DrawTextLayout(psas(0).TextLayout, PointF.Empty)
                g.DrawTextLayout(psas(1).TextLayout, PointF.Empty)
                If tls.SplitResult <> SplitResult.Split Then
                    '' 章节结束,找出下一章的页面剩余高度:
                    contentBottom = tl.ContentY + tl.ContentHeight
                    contentBottom = Math.Max(contentBottom, psas(0).TextLayout.ContentRectangle.Bottom)
                    contentBottom = Math.Max(contentBottom, psas(1).TextLayout.ContentRectangle.Bottom)
                    '' 打印完成章节:
                    Exit While
                End If
                '' 在新页面上继续打印章节:
                psas(0).MarginTop = margin
                psas(1).MarginTop = margin
                doc.Pages.Add()
            End While
            '' 下一章 - 查明当前页面是否有足够的空间来开始新的章节:
            If contentBottom + captionH < pageHeight * 0.8F Then
                '' 在当前页面开始新章节:
                contentBottom += pageHeight * 0.05F
                tlCaption.MarginTop = contentBottom
                tl.MarginTop = contentBottom + captionH
                psas(0).MarginTop = tl.MarginTop
                psas(1).MarginTop = tl.MarginTop
            ElseIf i < NChapters Then
                '' 在新的一页上开始新的篇章:
                tlCaption.MarginTop = margin
                tl.MarginTop = margin + captionH
                psas(0).MarginTop = tl.MarginTop
                psas(1).MarginTop = tl.MarginTop
                doc.Pages.Add()
            End If
        Next
        ''
        '' 完毕:
        doc.Save(stream)
        Return doc.Pages.Count
    End Function
End Class