Czytanie zawartości PDF za pomocą itextsharp dll w VB.NET lub C #

80

Jak czytać zawartość PDF za pomocą itextsharp z klasą Pdfreader. Mój plik PDF może zawierać zwykły tekst lub obrazy tekstu.

user221185
źródło
iTextSharp nazywa się teraz „iText 7 for .NET” lub „itext7-dotnet” na github: link . Zaleca się dodanie itext7 z Nuget do swojego rozwiązania.
Peter Huber

Odpowiedzi:

184
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using System.IO;

public string ReadPdfFile(string fileName)
{
    StringBuilder text = new StringBuilder();

    if (File.Exists(fileName))
    {
        PdfReader pdfReader = new PdfReader(fileName);

        for (int page = 1; page <= pdfReader.NumberOfPages; page++)
        {
            ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
            string currentText = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);

            currentText = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText)));
            text.Append(currentText);
        }
        pdfReader.Close();
    }
    return text.ToString();
}
ShravankumarKumar
źródło
16
To powinno być oznaczone jako rozwiązanie! To działa świetnie dla mnie.
Carter Medlin
1
Dowolny konkretny powód pdfReader.Close (); dzieje się wewnątrz pętli for?
Czw 00 marca
8
po co w ogóle używać .Close () i nieusing (var pdfReader = ...) {}
Sebastian
2
Również ASCIIEncoding.Convertpowinno być, Encoding.Convertponieważ jest to metoda statyczna
Sebastian
Jeśli ktoś potrzebuje kodu podobnego do powyższego, implementacja krok po kroku, aby przeczytać tekst pdf w C #, oto link, qawithexperts.com/article/c-sharp/ ... dzięki
user3559462
15

LGPL / FOSS iTextSharp 4.x

var pdfReader = new PdfReader(path); //other filestream etc
byte[] pageContent = _pdfReader .GetPageContent(pageNum); //not zero based
byte[] utf8 = Encoding.Convert(Encoding.Default, Encoding.UTF8, pageContent);
string textFromPage = Encoding.UTF8.GetString(utf8);

Żadna z pozostałych odpowiedzi nie była dla mnie przydatna, wszystkie wydają się być skierowane do AGPL v5 z iTextSharp. Nigdy nie mogłem znaleźć żadnego odniesienia doSimpleTextExtractionStrategy lub LocationTextExtractionStrategyw wersji FOSS.

Coś jeszcze, co może być bardzo przydatne w połączeniu z tym:

const string PdfTableFormat = @"\(.*\)Tj";
Regex PdfTableRegex = new Regex(PdfTableFormat, RegexOptions.Compiled);

List<string> ExtractPdfContent(string rawPdfContent)
{
    var matches = PdfTableRegex.Matches(rawPdfContent);

    var list = matches.Cast<Match>()
        .Select(m => m.Value
            .Substring(1) //remove leading (
            .Remove(m.Value.Length - 4) //remove trailing )Tj
            .Replace(@"\)", ")") //unencode parens
            .Replace(@"\(", "(")
            .Trim()
        )
        .ToList();
    return list;
}

Spowoduje to wyodrębnienie danych tekstowych z pliku PDF, jeśli wyświetlany tekst Foo(bar)będzie zakodowany w pliku PDF, ponieważ (Foo\(bar\))Tjta metoda zwróci Foo(bar)zgodnie z oczekiwaniami. Ta metoda usunie wiele dodatkowych informacji, takich jak współrzędne lokalizacji z surowej zawartości pliku PDF.

Chris Marisic
źródło
1
Masz rację, zanim ekstrakcja tekstu 5.xx była obecna w iText tylko jako dowód słuszności koncepcji, aw iTextSharp wcale. To powiedziawszy, kod, który przedstawiasz, działa tylko w bardzo prymitywnych plikach PDF (używając czcionek z kodowaniem ASCII i Tj jako jedynym operatorem rysowania tekstu). Może być użyteczny w bardzo kontrolowanych środowiskach (w których można zapewnić tylko takie prymitywne pliki PDF), ale nie ogólnie.
mkl
Prawidłowe wyrażenie Regex to: (? <= () (. *?) (? =) Tj)
Diego
6

Oto rozwiązanie VB.NET oparte na rozwiązaniu ShravankumarKumar.

To TYLKO da ci tekst. Obrazy to inna historia.

Public Shared Function GetTextFromPDF(PdfFileName As String) As String
    Dim oReader As New iTextSharp.text.pdf.PdfReader(PdfFileName)

    Dim sOut = ""

    For i = 1 To oReader.NumberOfPages
        Dim its As New iTextSharp.text.pdf.parser.SimpleTextExtractionStrategy

        sOut &= iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage(oReader, i, its)
    Next

    Return sOut
End Function
Carter Medlin
źródło
Kiedy próbuję tego w moim pliku PDF, wyświetla mi się komunikat o błędzie „Wartość nie może być zerowa. Nazwa parametru: wartość”. Masz jakiś pomysł, o co chodzi?
Avi
sOut & = iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage (oReader, i, its). Dowiedziałem się też czegoś o tym błędzie. Jeśli wyjmę to z pętli i przeanalizuję poszczególne strony, działa na jednej stronie, a nie na drugiej. Jedyną różnicą między nimi, którą mogę stwierdzić, jest to, że problematyczna strona zawiera obrazy (których nie potrzebuję).
Avi
Jeśli chcesz rzucić okiem na plik PDF, mogę Ci go wysłać.
Avi
Używam .Net 4.0 i itextsharp 5.1.2.0 (właśnie pobrane). Tak samo ty?
Carter Medlin
.Net 3.5 oraz itextsharp 5.1.1. Zaktualizuję i zobaczę, czy problem został rozwiązany.
Avi
5

W moim przypadku chciałem tylko tekst z określonego obszaru dokumentu PDF, więc użyłem prostokąta wokół tego obszaru i wyodrębniłem z niego tekst. W poniższym przykładzie współrzędne dotyczą całej strony. Nie mam narzędzi do tworzenia plików PDF, więc gdy przyszedł czas na zawężenie prostokąta do określonej lokalizacji, odgadłem kilka współrzędnych, aż obszar został znaleziony.

Rectangle _pdfRect = new Rectangle(0f, 0f, 612f, 792f); // Entire page - PDF coordinate system 0,0 is bottom left corner.  72 points / inch
RenderFilter _renderfilter = new RegionTextRenderFilter(_pdfRect);
ITextExtractionStrategy _strategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), _filter);
string _text = PdfTextExtractor.GetTextFromPage(_pdfReader, 1, _strategy);

Jak zauważono w powyższych komentarzach, wynikowy tekst nie zachowuje żadnego z formatowania znalezionego w dokumencie PDF, jednak byłem zadowolony, że zachował zwroty karetki. W moim przypadku w tekście było wystarczająco dużo stałych, aby móc wyodrębnić wymagane wartości.

voidmain
źródło
0

Tutaj poprawiona odpowiedź ShravankumarKumar. Stworzyłem specjalne klasy dla stron, dzięki czemu można uzyskać dostęp do słów w pliku PDF na podstawie wierszy tekstu i słowa w tym wierszu.

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

//create a list of pdf pages
var pages = new List<PdfPage>();

//load the pdf into the reader. NOTE: path can also be replaced with a byte array
using (PdfReader reader = new PdfReader(path))
{
    //loop all the pages and extract the text
    for (int i = 1; i <= reader.NumberOfPages; i++)
    {
        pages.Add(new PdfPage()
        {
           content = PdfTextExtractor.GetTextFromPage(reader, i)
        });
    }
}

//use linq to create the rows and words by splitting on newline and space
pages.ForEach(x => x.rows = x.content.Split('\n').Select(y => 
    new PdfRow() { 
       content = y,
       words = y.Split(' ').ToList()
    }
).ToList());

Klasy niestandardowe

class PdfPage
{
    public string content { get; set; }
    public List<PdfRow> rows { get; set; }
}


class PdfRow
{
    public string content { get; set; }
    public List<string> words { get; set; }
}

Teraz możesz uzyskać słowo po wierszu i indeksie słów.

string myWord = pages[0].rows[12].words[4];

Lub użyj Linq, aby znaleźć wiersze zawierające określone słowo.

//find the rows in a specific page containing a word
var myRows = pages[0].rows.Where(x => x.words.Any(y => y == "myWord1")).ToList();

//find the rows in all pages containing a word
var myRows = pages.SelectMany(r => r.rows).Where(x => x.words.Any(y => y == "myWord2")).ToList();
VDWWD
źródło
-1
Public Sub PDFTxtToPdf(ByVal sTxtfile As String, ByVal sPDFSourcefile As String)
        Dim sr As StreamReader = New StreamReader(sTxtfile)
    Dim doc As New Document()
    PdfWriter.GetInstance(doc, New FileStream(sPDFSourcefile, FileMode.Create))
    doc.Open()
    doc.Add(New Paragraph(sr.ReadToEnd()))
    doc.Close()
End Sub
Radża
źródło
1
Pytanie brzmi jak czytać plik PDF, twoja odpowiedź to tworzenie go!
AaA