BalancedColumns.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' © MESCIUS inc. All rights reserved.
'' 
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 fontname = "Yu Gothic"
        Dim fontSize = 10
        '' 1/2" の余白(72 dpi は DsPdf で使用されるデフォルトの解像度です)。
        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.FontName = fontname
        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 を使用。
        Const captionH = 24.0F
        '' メインドキュメントの本文のテキストレイアウト(デフォルトの DsPdf 解像度は 72 dpi です)。
        Dim tl = New TextLayout(72)
        tl.DefaultFormat.FontName = fontname
        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 の配列。
        '' (第1列は 'main' 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 = $"第 {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.Count - 1, Nothing)))
            ''
            '' 最終章のテキストをクリアし、新しい章を追加します。
            tl.FirstLineIsStartOfParagraph = True
            tl.LastLineIsEndOfParagraph = True
            tl.Clear()
            tl.Append(Util.getString_ja(1, 1, 5, 2, 30, True))
            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
        ''
        '' PDF ドキュメントを保存します。
        doc.Save(stream)
        Return doc.Pages.Count
    End Function
End Class