Membaca dokumen PDF di .Net [ditutup]

90

Apakah ada perpustakaan sumber terbuka yang akan membantu saya membaca / mengurai dokumen PDF di .Net / C #?

JRoppert
sumber
1
Jawaban yang diberikan oleh Brock Nusser tampak seperti solusi paling mutakhir dan harus dianggap sebagai jawaban yang tepat untuk pertanyaan ini
ceetheman
Lebih banyak jawaban iTextSharp yang diperbarui di sini sejak pertanyaan ini ditutup.
VDWWD

Jawaban:

119

Sejak pertanyaan ini terakhir dijawab pada tahun 2008, iTextSharp telah meningkatkan api mereka secara dramatis. Jika Anda mengunduh versi terbaru api mereka dari http://sourceforge.net/projects/itextsharp/ , Anda dapat menggunakan potongan kode berikut untuk mengekstrak semua teks dari pdf menjadi string.

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;
        }   
    }
}
Brock Nusser
sumber
17
Anda mungkin tidak boleh menelepon kelas Anda PdfTextExtractorkarena akan berbenturan dengan kelas diiTextSharp.text.pdf.parser
Neil
2
iTextSharp telah pindah ke GitHub: github.com/itext/itextsharp
Amedee Van Gasse
1
mungkin mereka yang menjawab di sini bisa membantu di sini ?
Veverke
6
Sekarang dibayar untuk proyek komersial.
Nikolay Kostov
1
@iTextSharp sudah tidak digunakan lagi dan diganti dengan iText 7 github.com/itext/itext7-dotnet .
Matius
62

iTextSharp adalah taruhan terbaik. Digunakan untuk membuat laba-laba untuk lucene.Net sehingga dapat merayapi 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
    }
}
ceetheman
sumber
1
halo ceetheman, saya mencoba menggunakan kode yang telah Anda berikan di atas ... tetapi mendapatkan satu masalah. beberapa file pdf saya terbaca dengan baik tetapi di beberapa file pdf saya mendapat error "Index Out of Range" pada fungsi "CheckToken". dapatkah Anda membantu saya menyelesaikan ini?
Radhi
18
Mengacu pada sumber contoh Anda adalah ide yang bagus & sopan. Dalam hal ini kode sumber yang sama dapat ditemukan di sini codeproject.com/KB/cs/PDFToText.aspx
Myster
2
Saya punya masalah dengan kode ini, ia mengembalikan gobledegook yang terdiri dari huruf r dan n. Saya menggunakan PDFBox pada akhirnya.
Myster
Sangat aneh ... Saya mencolokkan pdf saya dan saya mendapat 1627 baris kosong di file teks saya ...
Ortund
1
Jawaban yang diberikan oleh Brock Nusser sepertinya merupakan solusi paling mutakhir dan patut dianggap sebagai jawaban yang tepat untuk pertanyaan ini.
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;
}
ShravankumarKumar
sumber
1
Satu-satunya metode yang berhasil untuk saya! Terima kasih Bung!
suap
PdfReader? Tolong tambahkan beberapa informasi.
DxTx
1
@DT lihat iTextSharp
dontbyteme
6

PDFClown mungkin membantu, tetapi saya tidak akan merekomendasikannya untuk aplikasi penggunaan besar atau berat.

Ilya Kochetov
sumber
LGPL berlisensi sehingga dapat digunakan untuk membuat perangkat lunak berpemilik komersial.
Sylwester Santorowski
1

Anda dapat melihat ini: http://www.codeproject.com/KB/showcase/pdfrasterizer.aspx Ini tidak sepenuhnya gratis, tetapi terlihat sangat bagus.

Alex

Alex Fort
sumber
1
Bisakah ini membantu untuk mengubah PDF menjadi teks mentah? Sepertinya alat itu mengubahnya menjadi gambar. Jadi saya memerlukan perpustakaan OCR maka :-)
JRoppert
1

aspose pdf bekerja dengan cukup baik. sekali lagi, Anda harus membayarnya

Kuvo
sumber
0

Ada juga LibHaru

http://libharu.org/wiki/Main_Page

Cetra
sumber
Tautan rusak. libharu.org
TernaryTopiary
1
Juga: "Saat ini libHaru tidak mendukung membaca dan mengedit file PDF yang ada dan sepertinya dukungan ini tidak akan pernah muncul." Apakah ini benar-benar relevan?
TernaryTopiary
0

Lihat perpustakaan Docotic.Pdf . Anda tidak perlu membuat kode sumber aplikasi Anda terbuka (seperti iTextSharp dengan lisensi virus AGPL 3, misalnya).

Docotic.Pdf dapat digunakan untuk membaca file PDF dan mengekstrak teks dengan atau tanpa format. Silakan lihat artikel yang menunjukkan cara mengekstrak teks dari PDF .

Penafian: Saya bekerja untuk Bit Miracle, vendor perpustakaan.

Bobrovsky
sumber
4
Hanya 30 hari gratis. Bukan pilihan yang baik ...
José Augustinho