Чтение PDF-документов в .Net

Есть ли библиотека с открытым исходным кодом, которая поможет мне читать / анализировать документы PDF в .Net / C#?

Ответ Брока Нуссера выглядит как самое современное решение, и его следует рассматривать как правильный ответ на этот вопрос.

ceetheman 11.01.2018 18:38

Более обновленный iTextSharp отвечает на здесь, поскольку этот вопрос закрыт.

VDWWD 10.01.2020 02:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
91
2
205 126
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Вы можете посмотреть на это: http://www.codeproject.com/KB/showcase/pdfrasterizer.aspx Это не совсем бесплатно, но выглядит очень красиво.

Алекс

Может ли это помочь преобразовать PDF в необработанный текст? Кажется, этот инструмент преобразует его в изображение. Тогда мне нужна библиотека OCR :-)

JRoppert 17.09.2008 17:33

PDFКлоун может помочь, но я бы не рекомендовал его для большого или интенсивного использования.

Лицензия LGPL, поэтому ее можно использовать для создания коммерческого проприетарного программного обеспечения.

Sylwester Santorowski 19.07.2019 11:43

Также есть LibHaru

http://libharu.org/wiki/Main_Page

Ссылка не работает. libharu.org

TernaryTopiary 08.05.2017 09:37

Также: «В настоящий момент libHaru не поддерживает чтение и редактирование существующих файлов PDF, и маловероятно, что эта поддержка когда-либо появится». Это действительно актуально?

TernaryTopiary 08.05.2017 09:38

iText - лучшая библиотека, которую я знаю. Первоначально написанный на Java, существует также порт .NET.

См. http://www.ujihara.jp/iTextdotNET/en/

Это не официальный порт, и ссылка в любом случае не работает. Официальный порт iText для .NET, iTextSharp, можно найти на GitHub: github.com/itext/itextsharp

Amedee Van Gasse 09.12.2015 18:39

http://www.c-sharpcorner.com/UploadFile/psingh/PDFFileGenerator12062005235236PM/PDFFileGenerator.aspx имеет открытый исходный код и может стать для вас хорошей отправной точкой.

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
    }
}

привет ceetheman, я пытался использовать код, который вы предоставили выше ... но возникла одна проблема. Некоторые мои файлы pdf читаются правильно, но в некоторых файлах pdf я получил ошибку «Индекс вне диапазона» в функции «CheckToken». не могли бы вы помочь мне решить эту проблему?

Radhi 22.02.2010 15:38

Ссылка на источник вашего примера - хорошая и вежливая идея. В этом случае тот же исходный код можно найти здесь codeproject.com/KB/cs/PDFToText.aspx

Myster 29.04.2010 04:22

У меня проблемы с этим кодом, он возвращает gobledegook, состоящий из букв r и n. В конце концов, я использовал PDFBox.

Myster 29.04.2010 07:39

Так странно ... Я подключил свой pdf, и в моем текстовом файле 1627 пустых строк ...

Ortund 05.10.2017 14:18

Ответ Брока Нуссера выглядит как самое современное решение, и его следует рассматривать как правильный ответ на этот вопрос.

ceetheman 11.01.2018 18:38

Привет! Мне очень нравится это решение, и оно отлично работает с англоязычными PDF-документами. Однако, используя французские PDF-документы, я получаю много "\ 036" и "\ 037" в текстовом файле. Я заметил, что вы используете CleanupContent для очистки документа. Но, используя ту же логику, «\ 037» может быть «F» или «», так что я немного потерялся. Не могли бы вы подробнее объяснить использование CleanupContent? Спасибо.

Oussama melki 07.09.2019 23:34

aspose pdf работает неплохо. опять же, вы должны заплатить за это

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;
}

Единственный метод, который у меня сработал! Спасибо чувак!

briba 07.07.2015 18:06

PdfReader? Пожалуйста, добавьте информацию.

DxTx 20.08.2018 06:01

@DT см. iTextSharp

dontbyteme 11.10.2018 11:25
Ответ принят как подходящий

Поскольку последний ответ на этот вопрос был дан в 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;
        }   
    }
}

Вероятно, вам не следует называть свой класс PdfTextExtractor, так как он будет конфликтовать с классом iTextSharp.text.pdf.parser.

Neil 12.06.2012 19:25

iTextSharp переехал на GitHub: github.com/itext/itextsharp

Amedee Van Gasse 09.12.2015 18:38

возможно, ответившие здесь могли помочь здесь?

Veverke 30.12.2015 17:36

Это было просто .... Спасибо

Abdul Saleem 16.01.2016 21:39

Сейчас платят за коммерческие проекты.

Nikolay Kostov 23.06.2016 14:11

@Veverke благодарим вас за добавление вашего окончательного решения в другой поток, о котором вы говорите здесь

Michael Bahig 23.04.2019 03:59

Лицензия AGPL, поэтому ее можно использовать для создания коммерческого программного обеспечения, только если она также имеет лицензию AGPL. Если вы хотите разрабатывать коммерческое проприетарное программное обеспечение, вы должны платить.

Sylwester Santorowski 19.07.2019 11:45

@iTextSharp устарел и заменен на iText 7 github.com/itext/itext7-dotnet.

Matthew 28.02.2020 00:13

Если кому-то нужен полный образец рабочего консольного приложения, похожий на приведенный выше код, посмотрите qawithexperts.com/article/c-sharp/…

Vikas Lalwani 06.08.2020 10:18

Взгляните на Библиотека Docotic.Pdf. Это не требует, чтобы вы открывали исходный код вашего приложения (например, iTextSharp с вирусной лицензией AGPL 3).

Docotic.Pdf можно использовать для чтения файлов PDF и извлечения текста с форматированием или без него. Пожалуйста, посмотрите статью, в которой показан как извлечь текст из PDF-файлов.

Отказ от ответственности: я работаю в Bit Miracle, разработчике библиотеки.

Только 30 дней бесплатно. Не лучший вариант ...

José Augustinho 04.07.2018 20:07

Другие вопросы по теме