ZugferdInfoExt.vb
'' 完毕:
Imports System.IO
Imports System.Drawing
Imports System.Linq
Imports System.Reflection
Imports System.Collections.Generic
Imports System.Globalization
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text
Imports s2industries.ZUGFeRD
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' 此示例演示如何从 ZUGFeRD 兼容的 XML 附件中检索发票数据。
'' 所有 ZUGFeRD 数据都会打印到此示例生成的 PDF 中。
'' See ZugferdInfo 以获取类似的示例,该示例打印 ZUGFeRD 数据的选定部分。

'' 包含 ZUGFeRD 数据的示例 PDF 发票,该示例将其用作输入
'' 由ZugferdInvoice生成​​。
'' 
'' ZUGFeRD 是基于 PDF 和 XML 文件格式的德国电子发票标准。
'' 它准备改变发票的处理方式,并可供任何类型的企业使用。
'' 它将使发件人和客户的发票处理更加高效。
'' 详细信息请参见什么是ZUGFeRD? 。
'' 
'' 此示例​​使用 ZUGFeRD-csharp 包
'' 解析附加到发票的 ZUGFeRD 兼容 XML。
Public Class ZugferdInfoExt
    Function CreatePDF(ByVal stream As Stream) As Integer
        '' The sample invoice with ZUGFeRD data:
        Dim invoicePdf = Path.Combine("Resources", "PDFs", "zugferd-invoice.pdf")

        '' Output document:
        Dim doc = New GcPdfDocument()
        Using fs = File.OpenRead(invoicePdf)
            '' Load the ZUGFeRD compliant invoice PDF:
            Dim invoice = New GcPdfDocument()
            invoice.Load(fs)

            '' Get the ZUGFeRD attachment from the invoice by the ZUGFeRD 1.x standard file name:
            Dim attachment = invoice.EmbeddedFiles.Values.FirstOrDefault(Function(it) it.File.FileName = "ZUGFeRD-invoice.xml")
            If attachment IsNot Nothing Then
                Using xmlstream = attachment.GetStream()
                    '' Load the invoice descriptor:
                    Dim descriptor = InvoiceDescriptor.Load(xmlstream)

                    Dim tl = New TextLayout(72)
                    tl.MaxWidth = doc.PageSize.Width
                    tl.MaxHeight = doc.PageSize.Height
                    tl.MarginAll = tl.Resolution
                    tl.DefaultTabStops = 24

                    '' Recursively render all InvoiceDescriptor properties to text layout:
                    tl.AppendLine($"{NameOf(InvoiceDescriptor)}:", _tfStrong)
                    RenderProperties(descriptor, tl, 1)

                    '' Write text layout to output PDF
                    tl.PerformLayout(True)
                    Dim topt = New TextSplitOptions(tl)
                    While (True)
                        Dim rest As TextLayout = Nothing
                        Dim splitResult = tl.Split(topt, rest)
                        doc.Pages.Add().Graphics.DrawTextLayout(tl, PointF.Empty)
                        If splitResult <> SplitResult.Split Then
                            Exit While
                        End If
                        tl = rest
                    End While
                    '' Done:
                    doc.Save(stream)
                    Return doc.Pages.Count
                End Using
            Else
                Return 0
            End If
        End Using
    End Function

    '' Recursively print all source's properties to text layout:
    Shared Sub RenderProperties(ByVal source As Object, ByVal tl As TextLayout, ByVal level As Integer)
        If source Is Nothing Then
            Return
        End If
        Dim props = source.GetType().GetProperties()
        For Each prop In props
            RenderProperty(prop, source, tl, level)
        Next
    End Sub

    '' Text formats for output:
    Private Shared ReadOnly _tfData = New TextFormat() With {
        .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf")),
        .FontSize = 12
    }
    Private Shared ReadOnly _tfStrong = New TextFormat(_tfData) With {
        .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeuib.ttf"))
    }
    Private Shared ReadOnly _tfLabels = New TextFormat(_tfData) With {
        .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeuii.ttf")),
        .FontSize = 11
    }

    '' Print a property:
    Shared Sub RenderProperty(ByVal prop As PropertyInfo, ByVal parent As Object, ByVal tl As TextLayout, ByVal level As Integer)
        Dim space = String.Empty
        For i = 0 To level - 1
            space += vbTab
        Next
        Dim name = prop.Name
        Dim value = prop.GetValue(parent, Nothing)
        If value Is Nothing Then
            tl.Append(space, _tfLabels)
            tl.AppendLine($"{name}:", _tfLabels)
        ElseIf (value.GetType().IsValueType OrElse value.GetType() Is GetType(String)) Then
            tl.Append(space, _tfLabels)
            tl.Append($"{name}: ", _tfLabels)
            tl.AppendLine(String.Format(CultureInfo.GetCultureInfo("en-US"), "{0}", value), _tfData)
        Else
            If TypeOf value Is IEnumerable(Of Object) Then
                Dim collection As IEnumerable(Of Object) = CType(value, IEnumerable(Of Object))
                Dim index = 0
                For Each item In collection
                    tl.Append(space, _tfLabels)
                    tl.AppendLine($"Collection item {name} [{index}]:", _tfStrong)
                    index += 1
                    RenderProperties(item, tl, level + 1)
                Next
            Else
                tl.Append(space, _tfLabels)
                tl.AppendLine($"Container {name}:", _tfStrong)
                RenderProperties(value, tl, level + 1)
            End If
        End If
    End Sub
End Class