Sar*_*nan 4 c# itextsharp c#-4.0
我在我的C#winform应用程序中使用iTextSharp.我想获得PDF文件中的特定段落.这可能在iTextSharp中吗?
Chr*_*aas 22
是的,不是.
首先是没有.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,它将从页面中获取所有原始文本.此方法的最后一个参数是实现ITextExtractionStrategy接口的对象.如果您创建自己的实现此接口的类,则可以处理每个文本运行并执行您自己的逻辑.
在这个接口中有一个调用的方法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) { }
}
Run Code Online (Sandbox Code Playgroud)
要打电话给我们,我们会这样做:
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]);
}
Run Code Online (Sandbox Code Playgroud)
我们实际上是丢弃了价值GetTextFromPage,而是检查了工人baselines和strings数组字段.下一步是比较基线并尝试确定如何将线组合在一起成为段落.
我应该注意,并非所有段落的间距都与单独的文本行不同.例如,如果您通过上面的代码运行下面创建的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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8402 次 |
| 最近记录: |