2017-09-06 4 views
1

PDFBox를 사용하여 PDF 파일의 좌표로 텍스트를 추출하려고합니다.PDFBox에서 스트립하는 경우의 텍스트 좌표

인터넷 (stackoverflow 너무)에서 발견 된 몇 가지 방법/정보를 섞어 보았지만 문제는 내가 좌표가 맞지 않습니다. 예를 들어, tex 위에 직사각형을 그릴 때 좌표를 사용하려고하면 rect가 다른 곳에 그려집니다.

TextLine.java

import java.util.List; 
    import org.apache.pdfbox.text.TextPosition; 

    /** 
    * 
    * @author samue 
    */ 
    public class TextLine { 
     public List<TextPosition> textPositions = null; 
     public String text = ""; 
    } 

myStripper.java

import java.io.IOException; 
    import java.util.ArrayList; 
    import java.util.List; 
    import org.apache.pdfbox.pdmodel.PDDocument; 
    import org.apache.pdfbox.pdmodel.PDPage; 
    import org.apache.pdfbox.text.PDFTextStripper; 
    import org.apache.pdfbox.text.TextPosition; 

    /* 
    * To change this license header, choose License Headers in Project Properties. 
    * To change this template file, choose Tools | Templates 
    * and open the template in the editor. 
    */ 

    /** 
    * 
    * @author samue 
    */ 
    public class myStripper extends PDFTextStripper { 
     public myStripper() throws IOException 
     { 
     } 

     @Override 
     protected void startPage(PDPage page) throws IOException 
     { 
      startOfLine = true; 
      super.startPage(page); 
     } 

     @Override 
     protected void writeLineSeparator() throws IOException 
     { 
      startOfLine = true; 
      super.writeLineSeparator(); 
     } 

     @Override 
     public String getText(PDDocument doc) throws IOException 
     { 
      lines = new ArrayList<TextLine>(); 
      return super.getText(doc); 
     } 

     @Override 
     protected void writeWordSeparator() throws IOException 
     { 
      TextLine tmpline = null; 

      tmpline = lines.get(lines.size() - 1); 
      tmpline.text += getWordSeparator(); 

      super.writeWordSeparator(); 
     } 


     @Override 
     protected void writeString(String text, List<TextPosition> textPositions) throws IOException 
     { 
      TextLine tmpline = null; 

      if (startOfLine) { 
       tmpline = new TextLine(); 
       tmpline.text = text; 
       tmpline.textPositions = textPositions; 
       lines.add(tmpline); 
      } else { 
       tmpline = lines.get(lines.size() - 1); 
       tmpline.text += text; 
       tmpline.textPositions.addAll(textPositions); 
      } 

      if (startOfLine) 
      { 
       startOfLine = false; 
      } 
      super.writeString(text, textPositions); 
     } 

     boolean startOfLine = true; 
     public ArrayList<TextLine> lines = null; 

    } 
를 (단지 테스트하기 위해 매우 빠른 기록 된 스타일을 판단하지 마십시오) 내 코드입니다

AWT 버튼을 클릭 이벤트

private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {          
    // TODO add your handling code here: 
    try { 
     File file = new File("C:\\Users\\samue\\Desktop\\mwb_I_201711.pdf"); 
     PDDocument doc = PDDocument.load(file); 

     myStripper stripper = new myStripper(); 

     stripper.setStartPage(1); // fix it to first page just to test it 
     stripper.setEndPage(1); 
     stripper.getText(doc); 

     TextLine line = stripper.lines.get(1); // the line i want to paint on 

     float minx = -1; 
     float maxx = -1; 

     for (TextPosition pos: line.textPositions) 
     { 
      if (pos == null) 
       continue; 

      if (minx == -1 || pos.getTextMatrix().getTranslateX() < minx) { 
       minx = pos.getTextMatrix().getTranslateX(); 
      } 
      if (maxx == -1 || pos.getTextMatrix().getTranslateX() > maxx) { 
       maxx = pos.getTextMatrix().getTranslateX(); 
      } 
     } 

     TextPosition firstPosition = line.textPositions.get(0); 
     TextPosition lastPosition = line.textPositions.get(line.textPositions.size() - 1); 

     float x = minx; 
     float y = firstPosition.getTextMatrix().getTranslateY(); 
     float w = (maxx - minx) + lastPosition.getWidth(); 
     float h = lastPosition.getHeightDir(); 

     PDPageContentStream contentStream = new PDPageContentStream(doc, doc.getPage(0), PDPageContentStream.AppendMode.APPEND, false); 

     contentStream.setNonStrokingColor(Color.RED); 
     contentStream.addRect(x, y, w, h); 
     contentStream.fill(); 
     contentStream.close(); 

     File fileout = new File("C:\\Users\\samue\\Desktop\\pdfbox.pdf"); 
     doc.save(fileout); 
     doc.close(); 
    } catch (Exception ex) { 

    } 
}          

제안 사항? 내가 도대체 ​​뭘 잘못하고있는 겁니까?

+0

나는 당신의 코드를 이해하지 못했다. PDF에서 y = 0은 맨 위가 아니라 맨 아래임을 유의하십시오. 다음은 텍스트 추출 좌표를 사용하는 방법을 이해하는 데 도움이되는 예제입니다. https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/ DrawPrintTextLocations.java?view = markup & sortby = date –

+1

'PDPContentStream' 생성자를 다른 부울 인수'resetContext'와 함께 사용하고'true'로 설정해 보았습니까? – mkl

+0

예 저는 0이 맨 아래에 있다는 것을 알고 있습니다. 이것이 getY() 또는 getYDirAdj() 대신 .getTextMatrix(). getTranslateY()를 사용한 이유입니다. 나는 resetContext를 사용해 보았지만 아무 도움도받지 않았다. 이제 그 소스 코드를 살펴볼 것입니다. 업데이트 할 것입니다. 감사합니다. –

답변

2

이는 좌표 정규화가 과도한 PdfTextStripper의 또 다른 경우입니다. 당신처럼 나는 (getX()getY 대신)을 사용하여 하나의 실제 좌표를 얻을 것이라고 생각했지만,이 매트릭스 값도 수정해야합니다 (적어도 PDFBox 2.0.x에서는 1.8을 체크하지 않았습니다. .x) 행렬에 자르기 상자의 왼쪽 아래 모서리를 만드는 변환이 곱해지기 때문입니다.

따라서 상자 (자르기 상자의 왼쪽 하단이 원점이 아닌 경우)에서 값을 수정해야합니다.

 PDRectangle cropBox = doc.getPage(0).getCropBox(); 

     float x = minx + cropBox.getLowerLeftX(); 
     float y = firstPosition.getTextMatrix().getTranslateY() + cropBox.getLowerLeftY(); 

대신

without correction

에 의해

 float x = minx; 
     float y = firstPosition.getTextMatrix().getTranslateY(); 

를 교체하여 지금 얻을

with x,y correction

분명히, 그러나, 당신은 또한 다소 높이를 수정해야합니다.

// 1/2 the bbox is used as the height todo: why? 
    float glyphHeight = bbox.getHeight()/2; 

(LegacyPDFStreamEngine에서 showGlyph(...)에서, PdfTextStripper의 부모 클래스) 글꼴의 경계 상자가 실제로 일반적으로 너무 큰 반면

반 : 방법에 PdfTextStripper 텍스트의 높이를 결정 때문이다 그것으로 충분하지 않습니다.

+0

고마워요! 이 문제에 대한 해결책입니다, 정말 고마워요! 어쨌든, 단일 글리프를 기반으로 더 많은 작업을 수행하려고합니다. 끝나면 게시 할 것입니다. 다시 한 번 감사드립니다! –

+0

답이 * "문제의 해결책"* 인 경우 수락하십시오 (왼쪽 상단 모서리에있는 체크 표시를 클릭하십시오). – mkl

+0

죄송합니다. 알 수 없습니다. P –