การอ่านเอกสาร PDF ใน. Net [ปิด]


90

มีไลบรารีโอเพนซอร์สที่จะช่วยฉันในการอ่าน / แยกวิเคราะห์เอกสาร PDF ใน. Net / C # หรือไม่


1
คำตอบจาก Brock Nusser ดูเหมือนจะเป็นวิธีการแก้ปัญหาที่ทันสมัยที่สุดและควรได้รับการพิจารณาว่าเป็นคำตอบที่ถูกต้องสำหรับคำถามนี้
ceetheman

iTextSharp อัปเดตเพิ่มเติมที่นี่เนื่องจากคำถามนี้ถูกปิด
VDWWD

คำตอบ:


120

เนื่องจากคำถามนี้ได้รับคำตอบล่าสุดในปี 2008 iTextSharp ได้ปรับปรุง api อย่างมาก หากคุณดาวน์โหลดเวอร์ชันล่าสุดของ api จากhttp://sourceforge.net/projects/itextsharp/คุณสามารถใช้ข้อมูลโค้ดต่อไปนี้เพื่อแยกข้อความทั้งหมดจาก pdf เป็นสตริง

using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;

namespace PdfParser
{
    public static class PdfTextExtractor
    {
        public static string pdfText(string path)
        {
            PdfReader reader = new PdfReader(path);
            string text = string.Empty;
            for(int page = 1; page <= reader.NumberOfPages; page++)
            {
                text += PdfTextExtractor.GetTextFromPage(reader,page);
            }
            reader.Close();
            return text;
        }   
    }
}

17
คุณไม่ควรเรียกชั้นเรียนของคุณPdfTextExtractorเพราะมันจะปะทะกับชั้นในiTextSharp.text.pdf.parser
นีล

2
iTextSharp ได้ย้ายไปที่ GitHub: github.com/itext/itextsharp
Amedee Van Gasse

1
บางทีผู้ที่ตอบที่นี่สามารถช่วยได้ที่นี่ ?
Veverke

6
ตอนนี้จ่ายสำหรับโครงการเชิงพาณิชย์แล้ว
Nikolay Kostov

1
@iTextSharp ได้เลิกใช้ไปและแทนที่ด้วย iText 7 github.com/itext/itext7-dotnet
Matthew

62

iTextSharpเป็นทางออกที่ดีที่สุด ใช้เพื่อสร้างแมงมุมสำหรับ lucene.Net เพื่อให้สามารถรวบรวมข้อมูล PDF

using System;
using System.IO;
using iTextSharp.text.pdf;
using System.Text.RegularExpressions;

namespace Spider.Utils
{
    /// <summary>
    /// Parses a PDF file and extracts the text from it.
    /// </summary>
    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 ExtractText
        /// <summary>
        /// Extracts a text from a PDF file.
        /// </summary>
        /// <param name="inFileName">the full path to the pdf file.</param>
        /// <param name="outFileName">the output file name.</param>
        /// <returns>the extracted text</returns>
        public bool ExtractText(string inFileName, string outFileName)
        {
            StreamWriter outFile = null;
            try
            {
                // Create a reader for the given PDF file
                PdfReader reader = new PdfReader(inFileName);
                //outFile = File.CreateText(outFileName);
                outFile = new StreamWriter(outFileName, false, System.Text.Encoding.UTF8);

                Console.Write("Processing: ");

                int totalLen = 68;
                float charUnit = ((float)totalLen) / (float)reader.NumberOfPages;
                int totalWritten = 0;
                float curUnit = 0;

                for (int page = 1; page <= reader.NumberOfPages; page++)
                {
                    outFile.Write(ExtractTextFromPDFBytes(reader.GetPageContent(page)) + " ");

                    // Write the progress.
                    if (charUnit >= 1.0f)
                    {
                        for (int i = 0; i < (int)charUnit; i++)
                        {
                            Console.Write("#");
                            totalWritten++;
                        }
                    }
                    else
                    {
                        curUnit += charUnit;
                        if (curUnit >= 1.0f)
                        {
                            for (int i = 0; i < (int)curUnit; i++)
                            {
                                Console.Write("#");
                                totalWritten++;
                            }
                            curUnit = 0;
                        }

                    }
                }

                if (totalWritten < totalLen)
                {
                    for (int i = 0; i < (totalLen - totalWritten); i++)
                    {
                        Console.Write("#");
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (outFile != null) outFile.Close();
            }
        }
        #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 (input[i] == 213)
                        c = "'".ToCharArray()[0];

                    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)
                                        {
                                            resultString += c.ToString();
                                            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 CleanupContent(resultString);
            }
            catch
            {
                return "";
            }
        }

        private string CleanupContent(string text)
        {
            string[] patterns = { @"\\\(", @"\\\)", @"\\226", @"\\222", @"\\223", @"\\224", @"\\340", @"\\342", @"\\344", @"\\300", @"\\302", @"\\304", @"\\351", @"\\350", @"\\352", @"\\353", @"\\311", @"\\310", @"\\312", @"\\313", @"\\362", @"\\364", @"\\366", @"\\322", @"\\324", @"\\326", @"\\354", @"\\356", @"\\357", @"\\314", @"\\316", @"\\317", @"\\347", @"\\307", @"\\371", @"\\373", @"\\374", @"\\331", @"\\333", @"\\334", @"\\256", @"\\231", @"\\253", @"\\273", @"\\251", @"\\221"};
            string[] replace = {   "(",     ")",      "-",     "'",      "\"",      "\"",    "à",      "â",      "ä",      "À",      "Â",      "Ä",      "é",      "è",      "ê",      "ë",      "É",      "È",      "Ê",      "Ë",      "ò",      "ô",      "ö",      "Ò",      "Ô",      "Ö",      "ì",      "î",      "ï",      "Ì",      "Î",      "Ï",      "ç",      "Ç",      "ù",      "û",      "ü",      "Ù",      "Û",      "Ü",      "®",      "™",      "«",      "»",      "©",      "'" };

            for (int i = 0; i < patterns.Length; i++)
            {
                string regExPattern = patterns[i];
                Regex regex = new Regex(regExPattern, RegexOptions.IgnoreCase);
                text = regex.Replace(text, replace[i]);
            }

            return text;
        }

        #endregion

        #region CheckToken
        /// <summary>
        /// Check if a certain 2 character token just came along (e.g. BT)
        /// </summary>
        /// <param name="tokens">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 ((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;
                }
            }
            return false;
        }
        #endregion
    }
}

1
สวัสดีคุณ ceetheman ฉันพยายามใช้รหัสที่คุณให้ไว้ด้านบน ... แต่ได้รับปัญหาหนึ่งข้อ ไฟล์ pdf บางไฟล์ของฉันอ่านได้อย่างถูกต้อง แต่ในไฟล์ pdf บางไฟล์ฉันพบข้อผิดพลาด "Index Out of Range" ในฟังก์ชัน "CheckToken" คุณช่วยฉันแก้ไขปัญหานี้ได้ไหม
Radhi

18
การอ้างอิงแหล่งที่มาของตัวอย่างเป็นความคิดที่ดีและสุภาพ ในกรณีนี้สามารถพบซอร์สโค้ดเดียวกันได้ที่นี่codeproject.com/KB/cs/PDFToText.aspx
Myster

2
ฉันมีปัญหากับรหัสนี้มันส่งคืน gobledegook ซึ่งประกอบด้วยตัวอักษร r และ n ฉันใช้ PDFBox ในที่สุด
Myster

แปลกมาก ... ฉันเสียบ pdf ของฉันและฉันได้รับ 1627 บรรทัดว่างในไฟล์ข้อความของฉัน ...
Ortund

1
คำตอบที่ให้โดย Brock Nusser ดูเหมือนจะเป็นวิธีการแก้ปัญหาที่ทันสมัยที่สุดและควรได้รับการพิจารณาว่าเป็นคำตอบที่ถูกต้องสำหรับคำถามนี้
ceetheman

6
public string ReadPdfFile(object Filename, DataTable ReadLibray)
{
    PdfReader reader2 = new PdfReader((string)Filename);
    string strText = string.Empty;

    for (int page = 1; page <= reader2.NumberOfPages; page++)
    {
    ITextExtractionStrategy its = new iTextSharp.text.pdf.parser.SimpleTextExtractionStrategy();
    PdfReader reader = new PdfReader((string)Filename);
    String s = PdfTextExtractor.GetTextFromPage(reader, page, its);

    s = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(s)));
    strText = strText + s;
    reader.Close();
    }
    return strText;
}

1
วิธีเดียวที่ใช้ได้ผลสำหรับฉัน! ขอบคุณครับ!
briba

PdfReader? กรุณาเพิ่มข้อมูล
DxTx

1
@DT ดูiTextSharp
dontbyteme

6

PDFClownอาจช่วยได้ แต่ฉันไม่แนะนำให้ใช้กับแอปพลิเคชันขนาดใหญ่หรือใช้งานหนัก


LGPL ที่ได้รับอนุญาตเพื่อให้สามารถใช้สร้างซอฟต์แวร์เชิงพาณิชย์ที่เป็นกรรมสิทธิ์ได้
Sylwester Santorowski

3

iText เป็นห้องสมุดที่ดีที่สุดที่ฉันรู้จัก เดิมเขียนด้วย Java มีพอร์ต. NET ด้วยเช่นกัน

ดูhttp://www.ujihara.jp/iTextdotNET/en/


นั่นไม่ใช่พอร์ตอย่างเป็นทางการและลิงก์ก็เสียอยู่ดี พอร์ต. NET อย่างเป็นทางการของ iText, iTextSharp สามารถพบได้บน GitHub: github.com/itext/itextsharp
Amedee Van Gasse

1

คุณสามารถดูสิ่งนี้: http://www.codeproject.com/KB/showcase/pdfrasterizer.aspx มันไม่ได้ฟรี แต่มันก็ดูดีมาก

อเล็กซ์


1
สิ่งนี้สามารถช่วยแปลง PDF เป็นข้อความดิบได้หรือไม่? ดูเหมือนว่าเครื่องมือนั้นจะแปลงเป็นรูปภาพ ดังนั้นฉันต้องการห้องสมุด OCR แล้ว :-)
JRoppert




0

นอกจากนี้ยังมี LibHaru

http://libharu.org/wiki/Main_Page


ลิงก์เสีย libharu.org
TernaryTopiary

1
นอกจากนี้: "ในขณะนี้ libHaru ไม่รองรับการอ่านและแก้ไขไฟล์ PDF ที่มีอยู่และไม่น่าเป็นไปได้ที่การสนับสนุนนี้จะปรากฏขึ้น" สิ่งนี้เกี่ยวข้องจริงหรือไม่?
TernaryTopiary

0

เข้าไปดูที่ห้องสมุด Docotic.Pdfห้องสมุดไม่ต้องการให้คุณเปิดซอร์สโค้ดของแอปพลิเคชันของคุณ (เช่น iTextSharp ที่มีใบอนุญาตไวรัส AGPL 3 เป็นต้น)

Docotic.Pdf สามารถใช้เพื่ออ่านไฟล์ PDF และแยกข้อความโดยมีหรือไม่มีการจัดรูปแบบ โปรดดูบทความที่แสดงวิธีการแยกข้อความจาก PDFถึงวิธีการดึงข้อความจากไฟล์ PDF

ข้อจำกัดความรับผิดชอบ: ฉันทำงานให้กับ Bit Miracle ผู้ขายห้องสมุด


4
ฟรี 30 วันเท่านั้น ไม่ใช่ตัวเลือกที่ดี ...
José Augustinho
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.