GetTablePages.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' Copyright (c) GrapeCity inc. All rights reserved.
'' 
Imports System.IO
Imports System.Drawing
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.Recognition
Imports GrapeCity.Documents.Text

' テーブルからデータを抽出します。
Public Class GetTablePages
    Function CreatePDF(ByVal stream As Stream) As Integer
        Const DPI = 72.0F
        Const margin = 36.0F
        Dim doc = New GcPdfDocument()

        Dim tf = New TextFormat() With
        {
            .Font = Font.FromFile(Path.Combine("Resources", "Fonts", "ipag.ttc")),
            .FontSize = 9,
            .ForeColor = Color.Black
        }
        Dim tfHdr = New TextFormat(tf) With
        {
            .FontBold = True,
            .FontSize = 11,
            .ForeColor = Color.DarkBlue
        }
        Dim tfRed = New TextFormat(tf) With {.ForeColor = Color.Red}

        Using fs As New FileStream(Path.Combine("Resources", "PDFs", "product-list.pdf"), FileMode.Open, FileAccess.Read)
            Dim Page = doc.NewPage()
            Page.Landscape = True
            Dim g = Page.Graphics

            Dim rc = Util.AddNote(
                "このサンプルでは、複数のページに分割されたテーブル(商品価格表)を含むPDFを読み込み、" +
                "Page.GetTable()メソッドを用いて全ページのテーブルを抽出しています。" +
                "抽出されたデータは、行とセルのリストとして出力されます。" +
                "テーブルを含む元のPDFも、参照用に生成されるPDFに追加されます。",
                Page,
                New RectangleF(margin, margin, Page.Bounds.Width - margin * 2, Page.Bounds.Height - margin * 2))

            Dim tl = g.CreateTextLayout()
            tl.MaxWidth = Page.Bounds.Width
            tl.MaxHeight = Page.Bounds.Height
            tl.MarginAll = margin
            tl.MarginTop = rc.Bottom
            tl.DefaultTabStops = 165

            Dim docSrc = New GcPdfDocument()
            docSrc.Load(fs)

            For i = 0 To docSrc.Pages.Count - 1
                ' TableExtractOptionsを使用すると、テーブルのフォーマットの特殊性を考慮して、
                ' テーブルの認識を微調整することができます。
                Dim teo = New TableExtractOptions()
                Dim GetMinimumDistanceBetweenRows = teo.GetMinimumDistanceBetweenRows
                ' ここでは、行間の最小距離をわずかに長くして、テキストが折り返されているセルが
                ' 2つのセルであると誤認識されないようにしています。
                teo.GetMinimumDistanceBetweenRows =
                    Function(list)
                        Dim res = GetMinimumDistanceBetweenRows(list)
                        Return res * 1.2F
                    End Function
                Dim top = If(i = 0, DPI * 2, DPI)
                ' 指定された範囲にあるテーブルを取得します。
                Dim itable = docSrc.Pages(i).GetTable(New RectangleF(DPI * 0.25F, top, DPI * 8, DPI * 10.5F - top), teo)

                ' テキストレイアウトにテーブルデータを追加します。
                tl.Append(vbCrLf + $"元のドキュメントの {i + 1} ページ目のテーブルには、列が {itable.Cols.Count} 列と、行が {itable.Rows.Count} 行あります。データは以下のとおりです。", tfHdr)
                tl.AppendParagraphBreak()
                For row = 0 To itable.Rows.Count - 1
                    Dim tfmt = If(row = 0, tfHdr, tf)
                    For col = 0 To itable.Cols.Count - 1
                        Dim cell = itable.GetCell(row, col)
                        If col > 0 Then
                            tl.Append(vbTab, tfmt)
                        End If
                        If cell Is Nothing Then
                            tl.Append("<セルなし>", tfRed)
                        Else
                            tl.Append(cell.Text, tfmt)
                        End If
                    Next
                    tl.AppendLine()
                Next
            Next

            ' 抽出したデータを出力します。
            Dim tso As TextSplitOptions = New TextSplitOptions(tl) With {.RestMarginTop = margin, .MinLinesInFirstParagraph = 2, .MinLinesInLastParagraph = 2}
            tl.PerformLayout(True)
            While True
                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().Landscape = True
            End While

            ' 参照のため元のドキュメントを追加します。
            doc.MergeWithDocument(docSrc)

            doc.Save(stream)
            Return doc.Pages.Count
        End Using
    End Function
End Class