TextMap.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' © MESCIUS inc. All rights reserved.
'' 
Imports System.IO
Imports System.Drawing
Imports System.Numerics
Imports System.Collections.Generic
Imports System.Linq
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.Annotations
Imports GrapeCity.Documents.Pdf.Graphics
Imports GrapeCity.Documents.Pdf.TextMap

'' テキストマップ機能を使用する方法です。
'' PDF ファイルのページ内のテキスト行の座標を検索して、
'' 特定の位置にあるテキストを取得する方法を示します。
'' このサンプルでは請求書形式の既存のPDFファイルを読み込んでいます。
Public Class TextMap
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim page = doc.NewPage()

        Dim rc = Util.AddNote(
            "このサンプルは、TimeSheet サンプルによって作成された PDF を一時的な GcPdfDocument に" +
            "読み込み、最初のページのテキストマップを取得して、マップ内のすべての線分の座標と" +
            "テキストを出力します。" +
            "また、マップの HitTest メソッドを使用して PDF 内の特定の座標にあるテキストを検索し、" +
            "結果を印刷します。" +
            "このサンプルで使用されている元の TimeSheet.pdf は参照用に追加されています。",
            page)

        '' テキストの書式とレイアウトを設定します。
        Dim tf = New TextFormat() With
        {
            .Font = Util.getFont(),
            .FontSize = 12
        }
        Dim tfFound = New TextFormat() With
        {
            .Font = Util.getFont(),
            .FontBold = True,
            .FontSize = 13,
            .ForeColor = Color.DarkBlue
        }
        Dim tl = New TextLayout(72) With
        {
            .MaxWidth = doc.PageSize.Width,
            .MaxHeight = doc.PageSize.Height,
            .MarginAll = rc.Left,
            .MarginTop = rc.Bottom + 36,
            .TabStops = New List(Of TabStop)() From {New TabStop(72 * 2)}
        }
        Dim tso = New TextSplitOptions(tl) With
        {
            .MinLinesInFirstParagraph = 2,
            .MinLinesInLastParagraph = 2,
            .RestMarginTop = rc.Left
        }

        '' 任意の PDF を開き、一時的なドキュメントに読み込んで、マップを使用してテキストを検索します。
        Using fs = New FileStream(Path.Combine("Resources", "PDFs", "simple_invoicejp.pdf"), FileMode.Open, FileAccess.Read)
            Dim doc1 = New GcPdfDocument()
            doc1.Load(fs)
            Dim tmap = doc1.Pages(0).GetTextMap()

            '' ページ上の特定の座標にあるテキストを取得します。
            Dim tx0 As Single = 4.5F, ty0 As Single = 2.5F, tx1 As Single = 6.5F, ty1 As Single = 2.7F
            Dim htiFrom As HitTestInfo = tmap.HitTest(tx0 * 72, ty0 * 72)
            Dim htiTo As HitTestInfo = tmap.HitTest(tx1 * 72, ty1 * 72)
            Dim range1 As TextMapFragment = Nothing, text1 As String = Nothing
            tmap.GetFragment(htiFrom.Pos, htiTo.Pos, range1, text1)
            tl.AppendLine($"次の四角形領域の範囲にあるテキストを抽出 {vbCrLf} x={tx0:F2}"", y={ty0:F2}"", width={tx1 - tx0:F2}"", height={ty1 - ty0:F2}"" {vbCrLf}", tf)
            tl.AppendLine(text1, tfFound)
            tl.AppendLine()

            '' ページ上のすべてのテキスト断片とその位置を取得します。
            tl.AppendLine("ページ上に表示されたすべてのテキストをリスト化", tf)
            Dim range As TextMapFragment = Nothing, text As String = Nothing
            tmap.GetFragment(range, text)
            For Each tlf In range
                Dim coords = tmap.GetCoords(tlf)
                tl.Append($"座標位置({coords.B.X / 72:F2}"", {coords.B.Y / 72:F2}""):{vbTab}", tf)
                tl.AppendLine(tmap.GetText(tlf), tfFound)
            Next

            '' 結果を印刷します。
            tl.PerformLayout(True)
            While True
                '' 'rest' は、収まりきらなかったテキストを受け入れます。
                Dim rest As TextLayout = Nothing
                Dim splitResult = tl.Split(tso, rest)
                doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty)
                If splitResult <> SplitResult.Split Then
                    Exit While
                End If
                tl = rest
                doc.NewPage()
            End While

            '' 参照用に元の文書に追加します。
            doc.MergeWithDocument(doc1, New MergeDocumentOptions())

            '' PDF ドキュメントを保存します。
            doc.Save(stream)
        End Using
        Return doc.Pages.Count
    End Function
End Class