2012-01-13 76 views

回答

21

是的,沒有。

首先沒有。 PDF格式沒有文本結構的概念,如段落,句子甚至文字,它只是包含文本。事實是兩段文本彼此接近,所以我們認爲它們是結構化的,這是人類的事情。當在PDF中看到類似於三行的段落時,實際上生成PDF的程序實際上完成了將文本分成三個不相關的文本行然後在特定的x,y座標處繪製每行的工作。更糟糕的是,根據設計者的需求,每一行文字都可能由較小的文字組成,這些文字可能是文字,甚至只是字符。所以它可能是draw "the cat in the hat" at 10,10或者它可能是draw "t" at 10,10, then draw "h" at 14,10, then draw "e" at 18,10等等。實際上,Adobe InDesign等設計精良的程序的PDF格式非常常見。

現在是的。其實它也許是。如果你願意投入一點工作,你可能會讓iTextSharp做你正在尋找的東西。有一個名爲PdfTextExtractor的類,它有一個名爲GetTextFromPage的方法,它將從頁面獲取所有原始文本。該方法的最後一個參數是一個實現接口的對象。如果您創建自己的實現此接口的類,則可以處理每個文本運行並執行自己的邏輯。

在這個界面中有一個叫做RenderText的方法,每調用一次文本都會被調用。您將獲得一個iTextSharp.text.pdf.parser.TextRenderInfo對象,您可以從中獲取運行中的原始文本以及其他內容,例如當前座標,當前字體等。由於可視文本行可以由多個運行,您可以使用此方法將運行的基線(起始x座標)與上一次運行進行比較,以確定它是否屬於同一視線。

下面是一個接口的實現的例子:我們會做

public class TextAsParagraphsExtractionStrategy : iTextSharp.text.pdf.parser.ITextExtractionStrategy { 
     //Text buffer 
     private StringBuilder result = new StringBuilder(); 

     //Store last used properties 
     private Vector lastBaseLine; 

     //Buffer of lines of text and their Y coordinates. NOTE, these should be exposed as properties instead of fields but are left as is for simplicity's sake 
     public List<string> strings = new List<String>(); 
     public List<float> baselines = new List<float>(); 

     //This is called whenever a run of text is encountered 
     public void RenderText(iTextSharp.text.pdf.parser.TextRenderInfo renderInfo) { 
      //This code assumes that if the baseline changes then we're on a newline 
      Vector curBaseline = renderInfo.GetBaseline().GetStartPoint(); 

      //See if the baseline has changed 
      if ((this.lastBaseLine != null) && (curBaseline[Vector.I2] != lastBaseLine[Vector.I2])) { 
       //See if we have text and not just whitespace 
       if ((!String.IsNullOrWhiteSpace(this.result.ToString()))) { 
        //Mark the previous line as done by adding it to our buffers 
        this.baselines.Add(this.lastBaseLine[Vector.I2]); 
        this.strings.Add(this.result.ToString()); 
       } 
       //Reset our "line" buffer 
       this.result.Clear(); 
      } 

      //Append the current text to our line buffer 
      this.result.Append(renderInfo.GetText()); 

      //Reset the last used line 
      this.lastBaseLine = curBaseline; 
     } 

     public string GetResultantText() { 
      //One last time, see if there's anything left in the buffer 
      if ((!String.IsNullOrWhiteSpace(this.result.ToString()))) { 
       this.baselines.Add(this.lastBaseLine[Vector.I2]); 
       this.strings.Add(this.result.ToString()); 
      } 
      //We're not going to use this method to return a string, instead after callers should inspect this class's strings and baselines fields. 
      return null; 
     } 

     //Not needed, part of interface contract 
     public void BeginTextBlock() { } 
     public void EndTextBlock() { } 
     public void RenderImage(ImageRenderInfo renderInfo) { } 
    } 

要叫它:

 PdfReader reader = new PdfReader(workingFile); 
     TextAsParagraphsExtractionStrategy S = new TextAsParagraphsExtractionStrategy(); 
     iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage(reader, 1, S); 
     for (int i = 0; i < S.strings.Count; i++) { 
      Console.WriteLine("Line {0,-5}: {1}", S.baselines[i], S.strings[i]); 
     } 

我們實際上從GetTextFromPage,而是扔掉值檢查工作人員的baselinesstrings數組字段。接下來的步驟是比較基線並嘗試確定如何將線條組合成段落。

我應該注意到,並非所有段落的間距都與文本的各行不同。例如,如果通過上面的代碼運行下面創建的PDF,則會看到每行文本相距18個點,而不管該行是否構成新段落。如果您打開在Acrobat中創建的PDF,並覆蓋除了每行的第一個字母之外的所有內容,您會發現您的眼睛甚至無法區分換行符和分段符。

 using (FileStream fs = new FileStream(workingFile, FileMode.Create, FileAccess.Write, FileShare.None)) { 
      using (Document doc = new Document(PageSize.LETTER)) { 
       using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) { 
        doc.Open(); 
        doc.Add(new Paragraph("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.")); 
        doc.Add(new Paragraph("This")); 
        doc.Add(new Paragraph("Is")); 
        doc.Add(new Paragraph("A")); 
        doc.Add(new Paragraph("Test")); 
        doc.Close(); 
       } 
      } 
     } 
+0

@excellent explanation..i嘗試這種代碼來構建一個paragraph..but知道座標位置並沒有幫助me..because文本可以在任何地方在pdf..but很好的解釋一致..謝謝 – 2013-07-19 09:35:27

相關問題