VintaSoft Imaging .NET SDK 15.1: Документация для .NET разработчика
В этом разделе
PDF: Низкоуровневый доступ к структуре PDF документа
В этом разделе
PDF документ представлен в виде дерева объектов различного типа.

'Дерево PDF документа' (PdfTreeNodeBase) состоит из большого количества узкоспециализированных узлов, например: PdfPage - страница PDF документа, PdfImageResource - ресурс изображения и т.д.

Каждый узел дерева PDF документа ссылается на дерево низкоуровневых объектов.

'Дерево базовых объектов PDF документа' состоит из объектов базовых типов, например: PdfName - имя, PdfArray - массив и т. д. Класс PdfBasicObject является базовым классом для всех объектов в дереве базовых объектов PDF документа.

Базовые типы

'Дерево базовых объектов PDF документа' состоит из узлов следующих типов:
Любой базовый объект в PDF файле может быть помечен как косвенный объект. Это дает объекту уникальный идентификатор объекта (PdfIndirectObject.Number и PdfIndirectObject.Generation), по которому другие объекты могут ссылаться на него, используя косвенную ссылку. Все потоки (PdfStream) должны быть косвенными объектами.

Метод PdfIndirectObject.GetByReference позволяет получить косвенный объект, на который ссылается ссылка. Метод PdfIndirectObject.GetReference позволяет получить косвенную ссылку на косвенный объект. Метод PdfIndirectObject.Create позволяет создать косвенный объект, при этом идентификатор для объекта будет присвоен автоматически.

Вот C#/VB.NET код, который демонстрирует, как создать простой PDF документ, используя дерево базовых объектов PDF документа:
/// <summary>
/// Creates a single page PDF document using only PDF basic types (basic PDF tree).
/// </summary>
/// <param name="outputPdfFilename">The output PDF filename.</param>
public static void CreatePdfDocumentUseBasicTypes(string outputPdfFilename)
{
    using (Vintasoft.Imaging.Pdf.PdfDocument document = 
        new Vintasoft.Imaging.Pdf.PdfDocument(Vintasoft.Imaging.Pdf.PdfFormat.Pdf_14))
    {
        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary catalog = 
            GetBasicObject<Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary>(document.Catalog.BasicObject);

        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary pages = 
            GetBasicObject<Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary>(catalog["Pages"]);

        pages["Count"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfIntegerNumber(1);
        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary page = 
            new Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document);
        pages["Kids"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfArray(document, 
            Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, page).GetReference());

        page["Type"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Page");
        page["Parent"] = catalog["Pages"];
        page["MediaBox"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfArray(document,
            Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(0),
            Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(0),
            Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(300),
            Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(400));

        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary font = 
            new Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document);
        font["Type"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Font");
        font["Subtype"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Type1");
        font["BaseFont"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Times-Roman");
        font["Encoding"] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfName("WinAnsiEncoding");

        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary fontResources = 
            new Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document);
        fontResources["F1"] = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, font).GetReference();
        Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary pageResources = 
            new Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document);
        pageResources["Font"] = fontResources;
        page["Resources"] = pageResources;

        string content = "q /F1 20 Tf BT 100 200 Td (Hello World!) Tj ET Q";
        Vintasoft.Imaging.Pdf.BasicTypes.PdfStream contentStream = 
            new Vintasoft.Imaging.Pdf.BasicTypes.PdfStream(document);
        contentStream.SetBytes(
            System.Text.Encoding.ASCII.GetBytes(content), 
            Vintasoft.Imaging.Pdf.PdfCompression.None,
            Vintasoft.Imaging.Pdf.PdfCompressionSettings.DefaultSettings);
        page["Contents"] = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, contentStream).GetReference();

        document.Save(outputPdfFilename);
    }
}

/// <summary>
/// Gets the basic object of specified type.
/// </summary>
/// <typeparam name="T">Type of basic object.</typeparam>
/// <param name="obj">The basic object.</param>
private static T GetBasicObject<T>(Vintasoft.Imaging.Pdf.BasicTypes.PdfBasicObject obj)
    where T : Vintasoft.Imaging.Pdf.BasicTypes.PdfBasicObject
{
    if (obj is T)
        return (T)obj;
    if (obj is Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference)
        return GetBasicObject<T>(
            Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.GetByReference(((
                Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference)obj)));
    if (obj is Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject)
        return GetBasicObject<T>(((Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject)obj).Value);
    if (obj is Vintasoft.Imaging.Pdf.BasicTypes.PdfStream)
        return GetBasicObject<T>(((Vintasoft.Imaging.Pdf.BasicTypes.PdfStream)obj).Dictionary);
    return (T)obj;
}
''' <summary>
''' Creates a single page PDF document using only PDF basic types (basic PDF tree).
''' </summary>
''' <param name="outputPdfFilename">The output PDF filename.</param>
Public Shared Sub CreatePdfDocumentUseBasicTypes(outputPdfFilename As String)
    Using document As New Vintasoft.Imaging.Pdf.PdfDocument(Vintasoft.Imaging.Pdf.PdfFormat.Pdf_14)
        Dim catalog As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetBasicObject(Of Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary)(document.Catalog.BasicObject)

        Dim pages As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetBasicObject(Of Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary)(catalog("Pages"))

        pages("Count") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfIntegerNumber(1)
        Dim page As New Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document)
        pages("Kids") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfArray(document, Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, page).GetReference())

        page("Type") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Page")
        page("Parent") = catalog("Pages")
        page("MediaBox") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfArray(document, Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(0), Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(0), Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(300), Vintasoft.Imaging.Pdf.BasicTypes.PdfNumber.Create(400))

        Dim font As New Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document)
        font("Type") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Font")
        font("Subtype") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Type1")
        font("BaseFont") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfName("Times-Roman")
        font("Encoding") = New Vintasoft.Imaging.Pdf.BasicTypes.PdfName("WinAnsiEncoding")

        Dim fontResources As New Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document)
        fontResources("F1") = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, font).GetReference()
        Dim pageResources As New Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary(document)
        pageResources("Font") = fontResources
        page("Resources") = pageResources

        Dim content As String = "q /F1 20 Tf BT 100 200 Td (Hello World!) Tj ET Q"
        Dim contentStream As New Vintasoft.Imaging.Pdf.BasicTypes.PdfStream(document)
        contentStream.SetBytes(System.Text.Encoding.ASCII.GetBytes(content), Vintasoft.Imaging.Pdf.PdfCompression.None, Vintasoft.Imaging.Pdf.PdfCompressionSettings.DefaultSettings)
        page("Contents") = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(document, contentStream).GetReference()

        document.Save(outputPdfFilename)
    End Using
End Sub

''' <summary>
''' Gets the basic object of specified type.
''' </summary>
''' <typeparam name="T">Type of basic object.</typeparam>
''' <param name="obj">The basic object.</param>
Private Shared Function GetBasicObject(Of T As Vintasoft.Imaging.Pdf.BasicTypes.PdfBasicObject)(obj As Vintasoft.Imaging.Pdf.BasicTypes.PdfBasicObject) As T
    If TypeOf obj Is T Then
        Return DirectCast(obj, T)
    End If
    If TypeOf obj Is Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference Then
        Return GetBasicObject(Of T)(Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.GetByReference(DirectCast(obj, Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference)))
    End If
    If TypeOf obj Is Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject Then
        Return GetBasicObject(Of T)(DirectCast(obj, Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject).Value)
    End If
    If TypeOf obj Is Vintasoft.Imaging.Pdf.BasicTypes.PdfStream Then
        Return GetBasicObject(Of T)(DirectCast(obj, Vintasoft.Imaging.Pdf.BasicTypes.PdfStream).Dictionary)
    End If
    Return DirectCast(obj, T)
End Function


Доступ к базовым типам из узла PDF дерева

Каждый узел дерева PDF документа имеет ссылку (PdfTreeNodeBase.BasicObject) на дерево базовых объектов, из которых состоит этот узел. Доступ к корню дерева базовых объектов можно получить с помощью свойства PdfTreeNodeBase.BasicObject узла дерева PdfDocument.Catalog.

Обычно в качестве корня низкоуровневого дерева для узла дерева PDF документа выступает PdfDictionary. Эта структура позволяет хранить пользовательские данные.

Важно! Изменения в дереве базовых объектов PDF документа никак не контролируются. PDF документ может быть поврежден, если обязательные узлы PDF дерева будут изменены или удалены.

Вот C#/VB.NET код, который демонстрирует, как добавить пользовательские данные в узлы PDF дерева:
/// <summary>
/// Tests add/get custom data.
/// </summary>
public static void Test()
{
    // create PDF document
    using (Vintasoft.Imaging.Pdf.PdfDocument document = 
        new Vintasoft.Imaging.Pdf.PdfDocument("textCustomData.pdf", Vintasoft.Imaging.Pdf.PdfFormat.Pdf_14))
    {
        // add empty page to the PDF document
        Vintasoft.Imaging.Pdf.Tree.PdfPage page = document.Pages.Add(Vintasoft.Imaging.PaperSizeKind.A4);
        
        // add custom data to the PDF document catalog
        AddCustomStringData(document.Catalog, 
            "MyStringData", "Test String Value 1");                
        AddCustomStreamData(document.Catalog, 
            "MyStreamData", System.Text.Encoding.Unicode.GetBytes("Test Stream Data 1"));
        
        // add custom data to the PDF page
        AddCustomStringData(page, 
            "MyStringData", "Test String Value 2");
        AddCustomStreamData(page, 
            "MyStreamData", System.Text.Encoding.Unicode.GetBytes("Test Stream Data 2"));

        // save changes in PDF document
        document.SaveChanges();
    }

    // open PDF document
    using (Vintasoft.Imaging.Pdf.PdfDocument document = 
        new Vintasoft.Imaging.Pdf.PdfDocument("textCustomData.pdf"))
    {
        // read "/MyStringData" entry from the PDF document catalog
        System.Console.WriteLine(
            GetCustomStringData(document.Catalog, "MyStringData"));

        // read "/MyStreamData" entry from the PDF document catalog
        System.Console.WriteLine(
            System.Text.Encoding.Unicode.GetString(GetCustomStreamData(document.Catalog, "MyStreamData")));
        
        // read "/MyStringData" entry from PDF page
        System.Console.WriteLine(
            GetCustomStringData(document.Pages[0], "MyStringData"));
        
        // read "/MyStreamData" entry from PDF page
        System.Console.WriteLine(
            System.Text.Encoding.Unicode.GetString(GetCustomStreamData(document.Pages[0], "MyStreamData")));
    }
}       

/// <summary>
/// Adds the custom string data with the specified name to the specified PDF tree node.
/// </summary>
/// <param name="pdfTreeNode">The PDF tree node.</param>
/// <param name="dataName">The data name.</param>
/// <param name="dataValue">The data value.</param>
public static void AddCustomStringData(
    Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase pdfTreeNode,
    string dataName,
    string dataValue)
{
    Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary dictionary = GetDictionary(pdfTreeNode);
    if (dictionary.ContainsKey(dataName))
        throw new System.ArgumentException(string.Format("Key '{0}' already exists.", dataName));
    dictionary[dataName] = new Vintasoft.Imaging.Pdf.BasicTypes.PdfString(dataValue);
}

/// <summary>
/// Returns the custom string data with the specified name from the specified PDF tree node.
/// </summary>
/// <param name="pdfTreeNode">The PDF tree node.</param>
/// <param name="dataName">The data name.</param>
/// <returns>The custom string data with the specified name from the specified PDF tree node.</returns>
public static string GetCustomStringData(Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase pdfTreeNode, string dataName)
{
    Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary dictionary = GetDictionary(pdfTreeNode);
    if (dictionary.ContainsKey(dataName))
        return ((Vintasoft.Imaging.Pdf.BasicTypes.PdfString)dictionary[dataName]).ValueAsTextString;
    throw new System.ArgumentException(string.Format("Key '{0}' is not found.", dataName));
}

/// <summary>
/// Adds the custom stream data with the specified name to the specified PDF tree node.
/// </summary>
/// <param name="pdfTreeNode">The PDF tree node.</param>
/// <param name="dataName">The data name.</param>
/// <param name="dataValue">The data value.</param>
public static void AddCustomStreamData(
    Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase pdfTreeNode,
    string dataName,
    byte[] dataValue)
{
    Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary dictionary = GetDictionary(pdfTreeNode);
    if (dictionary.ContainsKey(dataName))
        throw new System.ArgumentException(string.Format("Key '{0}' already exists.", dataName));
    // create a stream
    Vintasoft.Imaging.Pdf.BasicTypes.PdfStream stream = 
        new Vintasoft.Imaging.Pdf.BasicTypes.PdfStream(pdfTreeNode.Document);
    // write data, compressed with ZIP compression, to the stream
    stream.SetBytes(dataValue, Vintasoft.Imaging.Pdf.PdfCompression.Zip, 
        Vintasoft.Imaging.Pdf.PdfCompressionSettings.DefaultSettings);
    // create an indirect object from the stream
    Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject indirectObject = 
        Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(pdfTreeNode.Document, stream);
    // set the reference for the specified entry
    dictionary[dataName] = indirectObject.GetReference();
}

/// <summary>
/// Returns the custom stream data with specified name from specified tree node.
/// </summary>
/// <param name="pdfTreeNode">The PDF tree node.</param>
/// <param name="dataName">The data name.</param>
public static byte[] GetCustomStreamData(Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase pdfTreeNode, string dataName)
{
    Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary dictionary = GetDictionary(pdfTreeNode);
    if (dictionary.ContainsKey(dataName))
    {
        Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference reference = 
            (Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference)dictionary[dataName];
        Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject indirectObject = 
            Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.GetByReference(reference);
        Vintasoft.Imaging.Pdf.BasicTypes.PdfStream stream = 
            (Vintasoft.Imaging.Pdf.BasicTypes.PdfStream)indirectObject.Value;
        return stream.GetBytes();
    }
    throw new System.ArgumentException(string.Format("Key '{0}' is not found.", dataName));
}

/// <summary>
/// Returns the dictionary from PDF tree node.
/// </summary>
/// <param name="node">The node.</param>
private static Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary GetDictionary(
    Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase node)
{
    Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary dictionary = 
        node.BasicObject as Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary;
    if (dictionary == null)
        throw new System.ArgumentException(
            string.Format("Node {0} is not a dictionary!", node.GetType().Name));
    return dictionary;
}
''' <summary>
''' Tests add/get custom data.
''' </summary>
Public Shared Sub Test()
    ' create PDF document
    Using document As New Vintasoft.Imaging.Pdf.PdfDocument("textCustomData.pdf", Vintasoft.Imaging.Pdf.PdfFormat.Pdf_14)
        ' add empty page to the PDF document
        Dim page As Vintasoft.Imaging.Pdf.Tree.PdfPage = document.Pages.Add(Vintasoft.Imaging.PaperSizeKind.A4)

        ' add custom data to the PDF document catalog
        AddCustomStringData(document.Catalog, "MyStringData", "Test String Value 1")
        AddCustomStreamData(document.Catalog, "MyStreamData", System.Text.Encoding.Unicode.GetBytes("Test Stream Data 1"))

        ' add custom data to the PDF page
        AddCustomStringData(page, "MyStringData", "Test String Value 2")
        AddCustomStreamData(page, "MyStreamData", System.Text.Encoding.Unicode.GetBytes("Test Stream Data 2"))

        ' save changes in PDF document
        document.SaveChanges()
    End Using

    ' open PDF document
    Using document As New Vintasoft.Imaging.Pdf.PdfDocument("textCustomData.pdf")
        ' read "/MyStringData" entry from the PDF document catalog
        System.Console.WriteLine(GetCustomStringData(document.Catalog, "MyStringData"))

        ' read "/MyStreamData" entry from the PDF document catalog
        System.Console.WriteLine(System.Text.Encoding.Unicode.GetString(GetCustomStreamData(document.Catalog, "MyStreamData")))

        ' read "/MyStringData" entry from PDF page
        System.Console.WriteLine(GetCustomStringData(document.Pages(0), "MyStringData"))

        ' read "/MyStreamData" entry from PDF page
        System.Console.WriteLine(System.Text.Encoding.Unicode.GetString(GetCustomStreamData(document.Pages(0), "MyStreamData")))
    End Using
End Sub

''' <summary>
''' Adds the custom string data with the specified name to the specified PDF tree node.
''' </summary>
''' <param name="pdfTreeNode">The PDF tree node.</param>
''' <param name="dataName">The data name.</param>
''' <param name="dataValue">The data value.</param>
Public Shared Sub AddCustomStringData(pdfTreeNode As Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase, dataName As String, dataValue As String)
    Dim dictionary As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetDictionary(pdfTreeNode)
    If dictionary.ContainsKey(dataName) Then
        Throw New System.ArgumentException(String.Format("Key '{0}' already exists.", dataName))
    End If
    dictionary(dataName) = New Vintasoft.Imaging.Pdf.BasicTypes.PdfString(dataValue)
End Sub

''' <summary>
''' Returns the custom string data with the specified name from the specified PDF tree node.
''' </summary>
''' <param name="pdfTreeNode">The PDF tree node.</param>
''' <param name="dataName">The data name.</param>
''' <returns>The custom string data with the specified name from the specified PDF tree node.</returns>
Public Shared Function GetCustomStringData(pdfTreeNode As Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase, dataName As String) As String
    Dim dictionary As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetDictionary(pdfTreeNode)
    If dictionary.ContainsKey(dataName) Then
        Return DirectCast(dictionary(dataName), Vintasoft.Imaging.Pdf.BasicTypes.PdfString).ValueAsTextString
    End If
    Throw New System.ArgumentException(String.Format("Key '{0}' is not found.", dataName))
End Function

''' <summary>
''' Adds the custom stream data with the specified name to the specified PDF tree node.
''' </summary>
''' <param name="pdfTreeNode">The PDF tree node.</param>
''' <param name="dataName">The data name.</param>
''' <param name="dataValue">The data value.</param>
Public Shared Sub AddCustomStreamData(pdfTreeNode As Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase, dataName As String, dataValue As Byte())
    Dim dictionary As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetDictionary(pdfTreeNode)
    If dictionary.ContainsKey(dataName) Then
        Throw New System.ArgumentException(String.Format("Key '{0}' already exists.", dataName))
    End If
    ' create a stream
    Dim stream As New Vintasoft.Imaging.Pdf.BasicTypes.PdfStream(pdfTreeNode.Document)
    ' write data, compressed with ZIP compression, to the stream
    stream.SetBytes(dataValue, Vintasoft.Imaging.Pdf.PdfCompression.Zip, Vintasoft.Imaging.Pdf.PdfCompressionSettings.DefaultSettings)
    ' create an indirect object from the stream
    Dim indirectObject As Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.Create(pdfTreeNode.Document, stream)
    ' set the reference for the specified entry
    dictionary(dataName) = indirectObject.GetReference()
End Sub

''' <summary>
''' Returns the custom stream data with specified name from specified tree node.
''' </summary>
''' <param name="pdfTreeNode">The PDF tree node.</param>
''' <param name="dataName">The data name.</param>
Public Shared Function GetCustomStreamData(pdfTreeNode As Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase, dataName As String) As Byte()
    Dim dictionary As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = GetDictionary(pdfTreeNode)
    If dictionary.ContainsKey(dataName) Then
        Dim reference As Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference = DirectCast(dictionary(dataName), Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectReference)
        Dim indirectObject As Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject = Vintasoft.Imaging.Pdf.BasicTypes.PdfIndirectObject.GetByReference(reference)
        Dim stream As Vintasoft.Imaging.Pdf.BasicTypes.PdfStream = DirectCast(indirectObject.Value, Vintasoft.Imaging.Pdf.BasicTypes.PdfStream)
        Return stream.GetBytes()
    End If
    Throw New System.ArgumentException(String.Format("Key '{0}' is not found.", dataName))
End Function

''' <summary>
''' Returns the dictionary from PDF tree node.
''' </summary>
''' <param name="node">The node.</param>
Private Shared Function GetDictionary(node As Vintasoft.Imaging.Pdf.Tree.PdfTreeNodeBase) As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary
    Dim dictionary As Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary = TryCast(node.BasicObject, Vintasoft.Imaging.Pdf.BasicTypes.PdfDictionary)
    If dictionary Is Nothing Then
        Throw New System.ArgumentException(String.Format("Node {0} is not a dictionary!", node.[GetType]().Name))
    End If
    Return dictionary
End Function