2009-10-12 12 views
22

Zastanawiam się, czy można uzyskać tekst wewnątrz pliku PDF, używając tylko Javascript? Jeśli tak, czy ktoś może mi pokazać?tekst wyciągu z pdf w JavaScript

Wiem, że istnieją pewne biblioteki java, C#, etc po stronie serwera, ale wolałbym nie używać serwera. dzięki

Odpowiedz

46

Jest to starożytny pytanie, ale ponieważ pdf.js rozwija się przez lata, chciałbym dać nową odpowiedź. Oznacza to, że można to zrobić lokalnie, nie angażując żadnego serwera ani usługi zewnętrznej. Nowy plik pdf.js ma funkcję: page.getTextContent(). Możesz pobrać z tego treść tekstową. Zrobiłem to z powodzeniem z następującego kodu.

  1. To, co dostajesz na każdym etapie, to obietnica. Musisz kodować w następujący sposób: .then(function(){...}), aby przejść do następnego kroku.

    1) PDFJS.getDocument(data).then(function(pdf) {

    2) pdf.getPage(i).then(function(page){

    3) page.getTextContent().then(function(textContent){

  2. Co wreszcie jest tablicą ciąg textContent.bidiTexts[]. Łączysz je, aby uzyskać tekst 1 strony. Współrzędne bloków tekstowych służą do oceny, czy nowa linia lub spacja muszą być wstawione. (To może nie być całkowicie solidne, ale z mojego testu wydaje się, że jest w porządku.)

  3. Parametr wejściowy data musi być adresem typu URL lub ArrayBuffer. Użyłem funkcji ReadAsArrayBuffer (file) w FileReader API, aby uzyskać dane.

Mam nadzieję, że to pomoże.

Uwaga: Według niektórych innych użytkowników biblioteka zaktualizowała się i spowodowała pęknięcie kodu. Zgodnie z komentarzem: async5 poniżej, musisz zamienić textContent.bidiTexts na textContent.items.

function Pdf2TextClass(){ 
    var self = this; 
    this.complete = 0; 

    /** 
    * 
    * @param data ArrayBuffer of the pdf file content 
    * @param callbackPageDone To inform the progress each time 
    *  when a page is finished. The callback function's input parameters are: 
    *  1) number of pages done; 
    *  2) total number of pages in file. 
    * @param callbackAllDone The input parameter of callback function is 
    *  the result of extracted text from pdf file. 
    * 
    */ 
    this.pdfToText = function(data, callbackPageDone, callbackAllDone){ 
    console.assert(data instanceof ArrayBuffer || typeof data == 'string'); 
    PDFJS.getDocument(data).then(function(pdf) { 
    var div = document.getElementById('viewer'); 

    var total = pdf.numPages; 
    callbackPageDone(0, total);   
    var layers = {};   
    for (i = 1; i <= total; i++){ 
     pdf.getPage(i).then(function(page){ 
     var n = page.pageNumber; 
     page.getTextContent().then(function(textContent){ 
      if(null != textContent.bidiTexts){ 
      var page_text = ""; 
      var last_block = null; 
      for(var k = 0; k < textContent.bidiTexts.length; k++){ 
       var block = textContent.bidiTexts[k]; 
       if(last_block != null && last_block.str[last_block.str.length-1] != ' '){ 
        if(block.x < last_block.x) 
         page_text += "\r\n"; 
        else if (last_block.y != block.y && (last_block.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null)) 
         page_text += ' '; 
       } 
       page_text += block.str; 
       last_block = block; 
      } 

      textContent != null && console.log("page " + n + " finished."); //" content: \n" + page_text); 
      layers[n] = page_text + "\n\n"; 
      } 
      ++ self.complete; 
      callbackPageDone(self.complete, total); 
      if (self.complete == total){ 
      window.setTimeout(function(){ 
       var full_text = ""; 
       var num_pages = Object.keys(layers).length; 
       for(var j = 1; j <= num_pages; j++) 
        full_text += layers[j] ; 
       callbackAllDone(full_text); 
      }, 1000);    
      } 
     }); // end of page.getTextContent().then 
     }); // end of page.then 
    } // of for 
    }); 
}; // end of pdfToText() 
}; // end of class 
+1

"Pytanie starożytne", ale doskonałe odpowiedzi. Masz pojęcie, jak sprawić, by textLayer nie renderował znaków w poszczególnych elementach div, ale renderował je jako całe słowa? Dostaję całkiem duży hit wydajnościowy od próby użycia nakładania się warstwy tekstowej z divami ustawionymi bezwzględnie, ponieważ jest ich tak wiele. Jeśli wolisz to jako osobne rzeczywiste pytanie StackOverflow, zrobię to. – AJP

+0

@ gm2008 Próbowałem wyodrębnić tekst z pliku PDF za pomocą funkcji. Nie mogę jednak wyodrębnić tekstu. Pełny tekst zwraca pusty ciąg na końcu. Czy możesz mi pomóc? – suzee

+0

Nie mogłem tego przekonać (API się zmieniło). Dodałem mój własny przykład poniżej. – SchizoDuckie

-2

Jest to możliwe, ale:

  • trzeba by używać serwera w każdym razie, nie ma sposobu, można uzyskać zawartość pliku na komputerze użytkownika bez przenoszenia go do serwera iz powrotem
  • I nie ma znaczenia, że ​​ktokolwiek napisał taką bibliotekę jeszcze raz:

Więc jeśli masz trochę wolnego czasu, możesz nauczyć się formatu PDF i napisać taką bibliotekę sam, albo możesz po prostu użyć biblioteki po stronie serwera oczywiście.

6

Oto niektóre kodu JavaScript, który robi to, co ty chcesz przy użyciu PDF.js z http://hublog.hubmed.org/archives/001948.html:

var input = document.getElementById("input"); 
var processor = document.getElementById("processor"); 
var output = document.getElementById("output"); 

// listen for messages from the processor 
window.addEventListener("message", function(event){ 
    if (event.source != processor.contentWindow) return; 

    switch (event.data){ 
    // "ready" = the processor is ready, so fetch the PDF file 
    case "ready": 
     var xhr = new XMLHttpRequest; 
     xhr.open('GET', input.getAttribute("src"), true); 
     xhr.responseType = "arraybuffer"; 
     xhr.onload = function(event) { 
     processor.contentWindow.postMessage(this.response, "*"); 
     }; 
     xhr.send(); 
    break; 

    // anything else = the processor has returned the text of the PDF 
    default: 
     output.textContent = event.data.replace(/\s+/g, " "); 
    break; 
    } 
}, true); 

... a oto przykład:

http://git.macropus.org/2011/11/pdftotext/example/

+0

Podczas gdy powiązania te mogą odpowiedzieć na pytanie, lepiej jest m.in. istotne części odpowiedzi tutaj i podać link do odniesienia. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. –

+0

Cześć, próbuję tego, ale to nadal wymaga przesłania pliku na serwer. jak mogę przetwarzać pliki lokalnie, po stronie klienta? – Ben

+0

wypróbowałeś strategię w odpowiedzi @ gm2008? – rphv

7

nie mogłem przykład gm2008 do pracy (wewnętrzna struktura danych na PDF.js zmieniła podobno), więc napisałem moje własne rozwiązanie oparte w pełni obiecać, że nie używa żadnych elementów DOM, queryselectors lub na płótnie, używając zaktualizowanego pliku pdf.js z przykładu pod mozilla

Zjeżdża ścieżkę do pliku do przesłania, ponieważ używam go z węzłem-webkit. Musisz upewnić się, że masz cmapy pobrane i wskazane gdzieś i musisz pdf.js i pdf.worker.js, aby to działało.

/** 
    * Extract text from PDFs with PDF.js 
    * Uses the demo pdf.js from https://mozilla.github.io/pdf.js/getting_started/ 
    */ 
    this.pdfToText = function(data) { 

     PDFJS.workerSrc = 'js/vendor/pdf.worker.js'; 
     PDFJS.cMapUrl = 'js/vendor/pdfjs/cmaps/'; 
     PDFJS.cMapPacked = true; 

     return PDFJS.getDocument(data).then(function(pdf) { 
      var pages = []; 
      for (var i = 0; i < pdf.numPages; i++) { 
       pages.push(i); 
      } 
      return Promise.all(pages.map(function(pageNumber) { 
       return pdf.getPage(pageNumber + 1).then(function(page) { 
        return page.getTextContent().then(function(textContent) { 
         return textContent.items.map(function(item) { 
          return item.str; 
         }).join(' '); 
        }); 
       }); 
      })).then(function(pages) { 
       return pages.join("\r\n"); 
      }); 
     }); 
    } 

Wykorzystanie:

self.pdfToText(files[0].path).then(function(result) { 
     console.log("PDF done!", result); 
}) 
+0

Zobacz także https://github.com/mozilla/pdf.js/blob/master/examples/text-only/pdf2svg.js i https://github.com/mozilla/pdf.js/blob/master/examples /node/getinfo.js – async5

0

Dla wszystkich ludzi, którzy rzeczywiście chcą używać go na serwerze węzła:

/** 
* Created by velten on 25.04.16. 
*/ 
"use strict"; 
let pdfUrl = "http://example.com/example.pdf"; 
let request = require('request'); 
var pdfParser = require('pdf2json'); 

let pdfPipe = request({url: pdfUrl, encoding:null}).pipe(pdfParser); 

pdfPipe.on("pdfParser_dataError", err => console.error(err)); 
pdfPipe.on("pdfParser_dataReady", pdf => { 
    //optionally: 
    //let pdf = pdfParser.getMergedTextBlocksIfNeeded(); 

    let count1 = 0; 
    //get text on a particular page 
    for (let page of pdf.formImage.Pages) { 
     count1 += page.Texts.length; 
    } 

    console.log(count1); 
    pdfParser.destroy(); 
});