C# 如何在PDFSharp中遍历Pdf对象树?

C# 如何在PDFSharp中遍历Pdf对象树?,c#,pdf,pdf-generation,pdfsharp,C#,Pdf,Pdf Generation,Pdfsharp,我正在尝试使用c#中的PDFSharp遍历现有PDF文档中的PdfItem对象树 我想创建一个所有对象的层次结构,就像“PDF浏览器”的例子一样,但我希望它是一个树,而不是所有对象的平面列表 根节点是document.Internals.Catalog。我想遍历所有document.Internals.Catalog.Elements,直到我访问了每个元素 我遇到的一个问题是树中有循环引用,我不知道如何检测它们 有任何代码示例吗?阅读并分析整个集合,并构建自己的内存树。然后走到树上。mariha

我正在尝试使用c#中的PDFSharp遍历现有PDF文档中的PdfItem对象树

我想创建一个所有对象的层次结构,就像“PDF浏览器”的例子一样,但我希望它是一个树,而不是所有对象的平面列表

根节点是document.Internals.Catalog。我想遍历所有document.Internals.Catalog.Elements,直到我访问了每个元素

我遇到的一个问题是树中有循环引用,我不知道如何检测它们


有任何代码示例吗?

阅读并分析整个集合,并构建自己的内存树。然后走到树上。

marihanzo在PDFSharp论坛上的这篇文章对我们很有用:

我们遇到的唯一问题是处理其中包含\r\n的字段。这是一份代码副本,以防论坛帖子丢失

PDFParser.cs

public class PDFParser
{
    /// BT = Beginning of a text object operator
    /// ET = End of a text object operator
    /// Td move to the start of next line
    ///  5 Ts = superscript
    /// -5 Ts = subscript

    #region Fields

    #region _numberOfCharsToKeep
    /// <summary>
    /// The number of characters to keep, when extracting text.
    /// </summary>
    private static int _numberOfCharsToKeep = 15;
    #endregion

    #endregion



    #region ExtractTextFromPDFBytes
    /// <summary>
    /// This method processes an uncompressed Adobe (text) object
    /// and extracts text.
    /// </summary>
    /// <param name="input">uncompressed</param>
    /// <returns></returns>
    public string ExtractTextFromPDFBytes(byte[] input)
    {
        if (input == null || input.Length == 0) return "";

        try
        {
            string resultString = "";

            // Flag showing if we are we currently inside a text object
            bool inTextObject = false;

            // Flag showing if the next character is literal
            // e.g. '\\' to get a '\' character or '\(' to get '('
            bool nextLiteral = false;

            // () Bracket nesting level. Text appears inside ()
            int bracketDepth = 0;

            // Keep previous chars to get extract numbers etc.:
            char[] previousCharacters = new char[_numberOfCharsToKeep];
            for (int j = 0; j < _numberOfCharsToKeep; j++) previousCharacters[j] = ' ';


            for (int i = 0; i < input.Length; i++)
            {
                char c = (char)input[i];

                if (inTextObject)
                {
                    // Position the text
                    if (bracketDepth == 0)
                    {
                        if (CheckToken(new string[] { "TD", "Td" }, previousCharacters))
                        {
                            resultString += "\n\r";
                        }
                        else
                        {
                            if (CheckToken(new string[] { "'", "T*", "\"" }, previousCharacters))
                            {
                                resultString += "\n";
                            }
                            else
                            {
                                if (CheckToken(new string[] { "Tj" }, previousCharacters))
                                {
                                    resultString += " ";
                                }
                            }
                        }
                    }

                    // End of a text object, also go to a new line.
                    if (bracketDepth == 0 &&
                        CheckToken(new string[] { "ET" }, previousCharacters))
                    {

                        inTextObject = false;
                        resultString += " ";
                    }
                    else
                    {
                        // Start outputting text
                        if ((c == '(') && (bracketDepth == 0) && (!nextLiteral))
                        {
                            bracketDepth = 1;
                        }
                        else
                        {
                            // Stop outputting text
                            if ((c == ')') && (bracketDepth == 1) && (!nextLiteral))
                            {
                                bracketDepth = 0;
                            }
                            else
                            {
                                // Just a normal text character:
                                if (bracketDepth == 1)
                                {
                                    // Only print out next character no matter what.
                                    // Do not interpret.
                                    if (c == '\\' && !nextLiteral)
                                    {
                                        nextLiteral = true;
                                    }
                                    else
                                    {
                                        if (((c >= ' ') && (c <= '~')) ||
                                            ((c >= 128) && (c < 255)))
                                        {
                                            resultString += c.ToString();
                                        }

                                        nextLiteral = false;
                                    }
                                }
                            }
                        }
                    }
                }

                // Store the recent characters for
                // when we have to go back for a checking
                for (int j = 0; j < _numberOfCharsToKeep - 1; j++)
                {
                    previousCharacters[j] = previousCharacters[j + 1];
                }
                previousCharacters[_numberOfCharsToKeep - 1] = c;

                // Start of a text object
                if (!inTextObject && CheckToken(new string[] { "BT" }, previousCharacters))
                {
                    inTextObject = true;
                }
            }
            return resultString;
        }
        catch
        {
            return "";
        }
    }
    #endregion

    #region CheckToken
    /// <summary>
    /// Check if a certain 2 character token just came along (e.g. BT)
    /// </summary>
    /// <param name="search">the searched token</param>
    /// <param name="recent">the recent character array</param>
    /// <returns></returns>
    private bool CheckToken(string[] tokens, char[] recent)
    {
        foreach (string token in tokens)
        {
            if (token.Length > 1)
            {
                if ((recent[_numberOfCharsToKeep - 3] == token[0]) &&
                    (recent[_numberOfCharsToKeep - 2] == token[1]) &&
                    ((recent[_numberOfCharsToKeep - 1] == ' ') ||
                    (recent[_numberOfCharsToKeep - 1] == 0x0d) ||
                    (recent[_numberOfCharsToKeep - 1] == 0x0a)) &&
                    ((recent[_numberOfCharsToKeep - 4] == ' ') ||
                    (recent[_numberOfCharsToKeep - 4] == 0x0d) ||
                    (recent[_numberOfCharsToKeep - 4] == 0x0a))
                    )
                {
                    return true;
                }
            }
            else
            {
                return false;
            }

        }
        return false;
    }
    #endregion
}
公共类PDFParser
{
///BT=文本对象运算符的开头
///ET=文本对象运算符的结尾
///Td移动到下一行的起点
///5 Ts=上标
///-5 Ts=下标
#区域字段
#区域_charstokep编号
/// 
///提取文本时要保留的字符数。
/// 
私有静态int _numberofcharstokep=15;
#端区
#端区
#区域从PDFBytes提取文本
/// 
///此方法处理未压缩的Adobe(文本)对象
///并提取文本。
/// 
///未压缩
/// 
公共字符串ExtractTextFromPDFBytes(字节[]输入)
{
if(input==null | | input.Length==0)返回“”;
尝试
{
字符串resultString=“”;
//显示当前是否在文本对象中的标志
bool inTextObject=false;
//显示下一个字符是否为文字的标志
//例如,\\'获取'\'字符或'\('获取'('
bool nextLiteral=false;
//()括号嵌套级别。文本显示在()内
内括号深度=0;
//保留以前的字符以获取摘录编号等:
char[]previousCharacters=新字符[_numberOfCharsToKeep];
对于(int j=0;j<_numberOfCharsToKeep;j++)以前的字符[j]='';
for(int i=0;i=“”)和&(c=128)和&(c<255)))
{
结果字符串+=c.ToString();
}
nextLiteral=false;
}
}
}
}
}
}
//存储最近使用的字符
//当我们必须回去检查的时候
对于(int j=0;j<_charstokep-1;j++)
{
previousCharacters[j]=previousCharacters[j+1];
}
以前的字符[_numberofcharstokep-1]=c;
//文本对象的开头
如果(!inTextObject&&CheckToken(新字符串[]{“BT”},previo
   public override String ExtractText()
    {
        String outputText = "";
        try
        {
            PdfDocument inputDocument = PdfReader.Open(this._sDirectory + this._sFileName, PdfDocumentOpenMode.ReadOnly);

            foreach (PdfPage page in inputDocument.Pages)
            {
                for (int index = 0; index < page.Contents.Elements.Count; index++)
                {

                    PdfDictionary.PdfStream stream = page.Contents.Elements.GetDictionary(index).Stream;
                    outputText += new PDFParser().ExtractTextFromPDFBytes(stream.Value);
                }
            }

        }
        catch (Exception e)
        {
            PDF_ParseException oEx = new PDF_ParseException(this, e);
            oEx.Log();
            oEx.ToPdf(this._sDirectoryException);
        }
        return outputText;
    }