gpt4 book ai didi

c# - 如何在 C# 中使用 iTextSharp 获取 pdf 文件中的特定段落?

转载 作者:太空狗 更新时间:2023-10-29 23:56:06 26 4
gpt4 key购买 nike

我在我的 C# winform 应用程序中使用 iTextSharp。我想获取 PDF 文件中的特定段落。这在 iTextSharp 中可能吗?

最佳答案

是也不是。

首先是编号。 PDF 格式没有段落、句子甚至单词等文本结构的概念,它只有一连串的文本。事实上,两行文本彼此接近,以至于我们认为它们是结构化的,这是人类的事情。当您在 PDF 中看到看起来像三行段落的内容时,实际上生成 PDF 的程序实际上是将文本分成三个不相关的文本行,然后在特定的 x,y 坐标处绘制每一行。更糟糕的是,根据设计师的需要,每一行文本都可能由更小的行组成,这些行可能是单词,甚至只是字符。所以它可能是 在 10,10 处绘制“戴帽子的猫” 或者它可能是 在 10,10 处绘制“t”,然后在 14,10 处绘制“h”,然后在 18,10 处绘制“e”,依此类推。这对于来自 Adob​​e InDesign 等精心设计的程序的 PDF 实际上很常见。

现在是的。实际上它可能。如果您愿意做一些工作,您也许可以让 iTextSharp 做您正在寻找的事情。有一个名为 PdfTextExtractor 的类,它有一个名为 GetTextFromPage 的方法,可以从页面中获取所有原始文本。此方法的最后一个参数是一个实现 ITextExtractionStrategy 接口(interface)的对象。如果您创建自己的类来实现此接口(interface),您可以处理每行文本并执行您自己的逻辑。

在这个接口(interface)中有一个名为 RenderText 的方法,每次运行文本时都会调用该方法。您将获得一个 iTextSharp.text.pdf.parser.TextRenderInfo 对象,您可以从该对象中获取运行中的原始文本以及其他信息,例如它开始的当前坐标、当前字体等。由于文本的视线可以由多个运行组成,您可以使用此方法将运行的基线(起始 x 坐标)与上一次运行进行比较,以确定它是否是同一视线的一部分。

下面是该接口(interface)的一个实现示例:

    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();
}
}
}

关于c# - 如何在 C# 中使用 iTextSharp 获取 pdf 文件中的特定段落?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8846653/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com