2012-01-13 196 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

相关问题