一尘不染

在Itextsharp中使用ITextExtractionStrategy和LocationTextExtractionStrategy获取字符串的坐标

c#

我有一个PDF文件中,我使用ITextExtractionStrategy.Now从我以一个子类的字符串读入字符串My name is XYZ,并需要从PDF文件串的直角坐标,但没能做到it.On
google搜索我才知道那个LocationTextExtractionStrategy,但没有得到如何使用该工具来获取坐标。

这是代码。

ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
string currentText = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);
currentText = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText)));
text.Append(currentText);

string getcoordinate="My name is XYZ";

如何使用ITEXTSHARP获取此子字符串的直角坐标。

请帮忙。


阅读 1805

收藏
2020-05-19

共1个答案

一尘不染

这是实现的非常非常简单的版本。

在实施之前, _ 非常_
重要的一点是要知道PDF的“单词”,“段落”,“句子”等概念为零。此外,PDF中的文本不一定从左到右,从上到下地排列,并且没有任何意义。与非LTR语言有关。短语“
Hello World”可以写为PDF:

Draw H at (10, 10)
Draw ell at (20, 10)
Draw rld at (90, 10)
Draw o Wo at (50, 20)

也可以写成

Draw Hello World at (10,10)

ITextExtractionStrategy您需要实现的接口具有一种称为的方法RenderText,该方法将为PDF中的每个文本块调用一次。注意我说的是“块”而不是“词”。在上面的第一个示例中,对于这两个单词,该方法将被调用四次。在第二个示例中,这两个单词将被调用一次。这是要理解的非常重要的部分。PDF没有单词,因此,iTextSharp也没有单词。“单词”部分由您决定要100%解决。

同样,正如我上面所说,PDF没有段落。意识到这一点的原因是因为PDF无法将文本换行。每当您看到类似段落的内容时,实际上您会看到一个全新的文本绘图命令,该命令的y坐标与上一行不同。请参阅此内容以进行进一步讨论

下面的代码是一个非常简单的实现。为此,我LocationTextExtractionStrategy将已经实现的子类化ITextExtractionStrategy。在每次调用时,RenderText()我都会找到当前块的矩形(在此使用Mark的代码),并将其存储以备后用。我正在使用这个简单的帮助器类来存储这些块和矩形:

//Helper class that stores our rectangle and text
public class RectAndText {
    public iTextSharp.text.Rectangle Rect;
    public String Text;
    public RectAndText(iTextSharp.text.Rectangle rect, String text) {
        this.Rect = rect;
        this.Text = text;
    }
}

这是子类:

public class MyLocationTextExtractionStrategy : LocationTextExtractionStrategy {
    //Hold each coordinate
    public List<RectAndText> myPoints = new List<RectAndText>();

    //Automatically called for each chunk of text in the PDF
    public override void RenderText(TextRenderInfo renderInfo) {
        base.RenderText(renderInfo);

        //Get the bounding box for the chunk of text
        var bottomLeft = renderInfo.GetDescentLine().GetStartPoint();
        var topRight = renderInfo.GetAscentLine().GetEndPoint();

        //Create a rectangle from it
        var rect = new iTextSharp.text.Rectangle(
                                                bottomLeft[Vector.I1],
                                                bottomLeft[Vector.I2],
                                                topRight[Vector.I1],
                                                topRight[Vector.I2]
                                                );

        //Add this to our main collection
        this.myPoints.Add(new RectAndText(rect, renderInfo.GetText()));
    }
}

最后是上面的实现:

//Our test file
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");

//Create our test file, nothing special
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
    using (var doc = new Document()) {
        using (var writer = PdfWriter.GetInstance(doc, fs)) {
            doc.Open();

            doc.Add(new Paragraph("This is my sample file"));

            doc.Close();
        }
    }
}

//Create an instance of our strategy
var t = new MyLocationTextExtractionStrategy();

//Parse page 1 of the document above
using (var r = new PdfReader(testFile)) {
    var ex = PdfTextExtractor.GetTextFromPage(r, 1, t);
}

//Loop through each chunk found
foreach (var p in t.myPoints) {
    Console.WriteLine(string.Format("Found text {0} at {1}x{2}", p.Text, p.Rect.Left, p.Rect.Bottom));
}

我不能过分强调上述内容 _ _
考虑“单词”,这取决于您。TextRenderInfo传入的对象RenderText具有一种称为的方法GetCharacterRenderInfos(),您可能可以使用该方法来获取更多信息。GetBaseline() instead of如果您不关心字体的后代,则可能还需要使用GetDescentLine()`。

编辑

(我吃了一顿丰盛的午餐,所以感觉有所帮助。)

这是该版本的更新版本,MyLocationTextExtractionStrategy可完成我在下面的评论中所说的,即,它需要一个字符串来搜索并在每个块中搜索该字符串。由于列出的所有原因,在某些/许多/大多数/所有情况下,这将不起作用。如果子字符串在单个块中多次存在,则它还将仅返回第一个实例。连字和变音符号也可能与此混为一谈。

public class MyLocationTextExtractionStrategy : LocationTextExtractionStrategy {
    //Hold each coordinate
    public List<RectAndText> myPoints = new List<RectAndText>();

    //The string that we're searching for
    public String TextToSearchFor { get; set; }

    //How to compare strings
    public System.Globalization.CompareOptions CompareOptions { get; set; }

    public MyLocationTextExtractionStrategy(String textToSearchFor, System.Globalization.CompareOptions compareOptions = System.Globalization.CompareOptions.None) {
        this.TextToSearchFor = textToSearchFor;
        this.CompareOptions = compareOptions;
    }

    //Automatically called for each chunk of text in the PDF
    public override void RenderText(TextRenderInfo renderInfo) {
        base.RenderText(renderInfo);

        //See if the current chunk contains the text
        var startPosition = System.Globalization.CultureInfo.CurrentCulture.CompareInfo.IndexOf(renderInfo.GetText(), this.TextToSearchFor, this.CompareOptions);

        //If not found bail
        if (startPosition < 0) {
            return;
        }

        //Grab the individual characters
        var chars = renderInfo.GetCharacterRenderInfos().Skip(startPosition).Take(this.TextToSearchFor.Length).ToList();

        //Grab the first and last character
        var firstChar = chars.First();
        var lastChar = chars.Last();


        //Get the bounding box for the chunk of text
        var bottomLeft = firstChar.GetDescentLine().GetStartPoint();
        var topRight = lastChar.GetAscentLine().GetEndPoint();

        //Create a rectangle from it
        var rect = new iTextSharp.text.Rectangle(
                                                bottomLeft[Vector.I1],
                                                bottomLeft[Vector.I2],
                                                topRight[Vector.I1],
                                                topRight[Vector.I2]
                                                );

        //Add this to our main collection
        this.myPoints.Add(new RectAndText(rect, this.TextToSearchFor));
    }

您将使用与以前相同的方法,但是现在构造函数具有一个必需的参数:

var t = new MyLocationTextExtractionStrategy("sample");
2020-05-19