Ottieni l’esatta Stringposition in PDF

Ho provato a leggere un stream e speravo di ottenere per ogni stringa la posizione esatta (coordinate)

int size = reader.getXrefSize(); for (int i = 0; i < size; ++i) { PdfObject pdfObject = reader.getPdfObject(i); if ((pdfObject == null) || !pdfObject.isStream()) continue; PdfStream stream = (PdfStream) pdfObject; PdfObject obj = stream.get(PdfName.FILTER); if ((obj != null) && obj.toString().equals(PdfName.FLATEDECODE.toString())) { byte[] codedText = PdfReader.getStreamBytesRaw((PRStream) stream); byte[] text = PdfReader.FlateDecode(codedText); FileOutputStream o = new FileOutputStream(new File("/home..../Text" + i + ".txt")); o.write(text); o.flush(); o.close(); } } 

In realtà ho ottenuto la posizione

 ...... BT 70.9 800.9 Td /F1 14 Tf  Tj 10.1 0 Td  Tj 9.3 0 Td  Tj 3.9 0 Td  Tj 10.1 0 Td  Tj 18.7 0 Td  Tj 21 0 Td  Tj 24.9 0 Td  Tj 10.1 0 Td  Tj 28.8 0 Td  Tj 3.8 0 Td  Tj 8.6 0 Td  Tj 29.5 0 Td  Tj 16.4 0 Td  Tj 7.8 0 Td  Tj 12.4 0 Td  Tj 7.8 0 Td  Tj 3.9 0 Td  Tj 7.8 0 Td  Tj 7.8 0 Td  Tj 3.9 0 Td  Tj 10.8 0 Td  Tj 7.8 0 Td  Tj 10.9 0 Td  Tj ET ..... 

Ma non so quale stringa si adatti a quale posizione D’altra parte in Itext potrei semplicemente ottenere il testo normale con

 PdfReader reader = new PdfReader(new FileInputStream("/home/....xxx.pdf")); PdfTextExtractor extract = new PdfTextExtractor(reader); 

ma ovviamente senza alcuna posizione …

Quindi, come posso ottenere la posizione esatta per ogni testo (stringa, carattere, …)?

Come già sottolineato nel plinto e David van Driessche nelle loro risposte, l’estrazione del testo dal file PDF non è banale. Fortunatamente le classi nel pacchetto parser di iText fanno la maggior parte del pesante sollevamento per te. Hai già trovato almeno una class da quel pacchetto, PdfTextExtractor, ma questa class è essenzialmente un’utilità di utilità per l’utilizzo della funzionalità parser di iText se ti interessa solo il testo normale della pagina. Nel tuo caso devi guardare le classi in quel pacchetto più intensamente.

Un punto di partenza per ottenere informazioni sull’argomento dell’estrazione del testo con iText è la sezione 15.3 Analisi di PDF di iText in Action – 2a Edizione , in particolare il metodo extractText del campione ParsingHelloWorld.java :

 public void extractText(String src, String dest) throws IOException { PrintWriter out = new PrintWriter(new FileOutputStream(dest)); PdfReader reader = new PdfReader(src); RenderListener listener = new MyTextRenderListener(out); PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener); PdfDictionary pageDic = reader.getPageN(1); PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES); processor.processContent(ContentByteUtils.getContentBytesForPage(reader, 1), resourcesDic); out.flush(); out.close(); } 

che utilizza l’implementazione RenderListener MyTextRenderListener.java :

 public class MyTextRenderListener implements RenderListener { [...] /** * @see RenderListener#renderText(TextRenderInfo) */ public void renderText(TextRenderInfo renderInfo) { out.print("<"); out.print(renderInfo.getText()); out.print(">"); } } 

Mentre questa implementazione di RenderListener restituisce semplicemente il testo, l’object TextRenderInfo che ispeziona offre più informazioni:

 public LineSegment getBaseline(); // the baseline for the text (ie the line that the text 'sits' on) public LineSegment getAscentLine(); // the ascentline for the text (ie the line that represents the topmost extent that a string of the current font could have) public LineSegment getDescentLine(); // the descentline for the text (ie the line that represents the bottom most extent that a string of the current font could have) public float getRise() ; // the rise which represents how far above the nominal baseline the text should be rendered public String getText(); // the text to render public int getTextRenderMode(); // the text render mode public DocumentFont getFont(); // the font public float getSingleSpaceWidth(); // the width, in user space units, of a single space character in the current font public List getCharacterRenderInfos(); // details useful if a listener needs access to the position of each individual glyph in the text render operation 

Pertanto, se RenderListener oltre a ispezionare il testo con getText() considera anche getBaseline() o anche getAscentLine() e getDescentLine(). hai tutte le coordinate di cui avrai probabilmente bisogno.

PS: esiste una class wrapper per il codice in ParsingHelloWorld.extractText() , PdfReaderContentParser , che consente di scrivere semplicemente quanto segue dato un PdfReader reader, una int page, e un RenderListener renderListener:

 PdfReaderContentParser parser = new PdfReaderContentParser(reader); parser.processContent(page, renderListener); 

Se stai cercando di eseguire l’estrazione del testo, dovresti essere consapevole del fatto che si tratta di un processo decisamente non banale. Dovrai, come minimo, implementare una macchina RPN per eseguire il codice e accumulare trasformazioni ed eseguire tutti gli operatori di testo. Dovrai interpretare le metriche dei caratteri dal set corrente di risorse della pagina e probabilmente dovrai capire la codifica del testo.

Quando ho lavorato su Acrobat 1.0, ero responsabile del comando “Trova …” che includeva il tuo problema come sottoinsieme. Con un set più ricco di strumenti e più esperienza, ci sono voluti un paio di mesi per farlo bene.

Se vuoi capire quali sono i byte che stai vedendo per l’operatore Tj, dai un’occhiata alle specifiche del PDF: http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/ PDF32000_2008.pdf

Più in particolare – guarda la sezione 9.4.3. Per parafrasare quella sezione – ogni byte o sequenza potenzialmente di byte multipli deve essere cercato nel carattere usato per dipingere il testo (nell’esempio il carattere è identificato come / F1). Cercandoti troverai il carattere reale a cui si riferisce questo codice.

Tieni anche presente che l’ordine in cui vedi questi comandi di testo qui potrebbe non riflettere affatto l’ordine di lettura naturale, quindi dovrai capire in base alle posizioni che trovi quale sia effettivamente l’ordine corretto di questi personaggi.

Inoltre, tieni presente che il tuo file PDF potrebbe non contenere spazi, ad esempio. Poiché uno spazio può essere “falsificato” semplicemente spostando il carattere successivo un po ‘verso destra, alcuni generatori di PDF omettono gli spazi. Ma trovare una lacuna nelle coordinate potrebbe non essere un’interruzione di parole. Ad esempio, potrebbe anche essere la fine di una colonna.

Questo è davvero, davvero difficile – specialmente se si sta tentando di farlo su file PDF generici (al contrario di solo alcuni layout che si conoscono sempre provengono dalla stessa fonte). Ho scritto un editor di testo per PDF molto tempo fa per un prodotto chiamato PitStop Pro che è ancora in circolazione (non più affiliato ad esso) ed è stato un problema davvero difficile.

Se questa è un’opzione, prova a utilizzare una libreria o uno strumento esistente. Esistono certamente opzioni commerciali per tale biblioteca o strumento; Ho meno familiarità con le librerie open source / libere quindi non posso commentare in merito.