Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract text from PDF in JavaSript

I wonder if is possible to get the text inside of a PDF file by using only Javascript? If yes, can anyone show me how?

I know there are some server-side java, c#, etc libraries but I would prefer not using a server. thanks

like image 960
nacho4d Avatar asked Oct 12 '09 12:10

nacho4d


People also ask

How do I extract specific text from a PDF?

To extract information from a PDF in Acrobat DC, choose Tools > Export PDF and select an option. To extract text, export the PDF to a Word format or rich text format, and choose from several advanced options that include: Retain Flowing Text.

How do I read a PDF programmatically?

The very first and the easiest way of displaying the PDF file is to display it in the WebView. All you need to do is just put WebView in your layout and load the desired URL by using the webView. loadUrl() function. Now, run the application on your mobile phone and the PDF will be displayed on the screen.

Does JavaScript work in PDF?

NitroPDF and Adobe Acrobat definitely support JavaScript in PDF files.


2 Answers

This is an ancient question, but because pdf.js has been developing over the years, I would like to give a new answer. That is, it can be done locally without involving any server or external service. The new pdf.js has a function: page.getTextContent(). You can get the text content from that. I've done it successfully with the following code.

  1. What you get in each step is a promise. You need to code this way: .then( function(){...}) to proceed to the next step.

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

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

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

  2. What you finally get is an string array textContent.bidiTexts[]. You concatenate them to get the text of 1 page. Text blocks' coordinates are used to judge whether newline or space need to be inserted. (This may not be totally robust, but from my test it seems ok.)

  3. The input parameter data needs to be either a URL or ArrayBuffer type data. I used the ReadAsArrayBuffer(file) function in FileReader API to get the data.

Hope this helps.

Note: According to some other user, the library has updated and caused the code to break. According to the comment by async5 below, you need to replace textContent.bidiTexts with 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 
like image 137
gm2008 Avatar answered Sep 20 '22 00:09

gm2008


I couldn't get gm2008's example to work (the internal data structure on pdf.js has changed apparently), so I wrote my own fully promise-based solution that doesn't use any DOM elements, queryselectors or canvas, using the updated pdf.js from the example at mozilla

It eats a file path for the upload since i'm using it with node-webkit. You need to make sure you have the cmaps downloaded and pointed somewhere and you nee pdf.js and pdf.worker.js to get this working.

    /**      * 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");             });         });     } 

usage:

 self.pdfToText(files[0].path).then(function(result) {       console.log("PDF done!", result);  }) 
like image 40
SchizoDuckie Avatar answered Sep 20 '22 00:09

SchizoDuckie