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

' 表形式のデータを抽出
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", "segoeui.ttf")),
            .FontSize = 9,
            .ForeColor = Color.Black
        }
        Dim tfHdr = New TextFormat(tf) With
        {
            .Font = Font.FromFile(Path.Combine("Resources", "Fonts", "segoeuib.ttf")),
            .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は、参考として出力される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