java - 获取 PDF 中的确切字符串位置

标签 java pdf

我试图读取一个流,并希望为每个字符串获取确切的位置(坐标)

    int size = reader.getXrefSize();

    for (int i = 0; i < size; ++i)
    {
        PdfObject pdfObject = reader.getPdfObject(i);
        if ((pdfObject == null) || !pdfObject.isStream())
            continue;

        PdfStream stream = (PdfStream) pdfObject;
        PdfObject obj = stream.get(PdfName.FILTER);

        if ((obj != null) && obj.toString().equals(PdfName.FLATEDECODE.toString()))
        {
            byte[] codedText = PdfReader.getStreamBytesRaw((PRStream) stream);
            byte[] text = PdfReader.FlateDecode(codedText);
            FileOutputStream o = new FileOutputStream(new File("/home..../Text" + i + ".txt"));
            o.write(text);
            o.flush();
            o.close();
        }

    }

我居然得到了这样的位置

......
BT                  
70.9 800.9 Td /F1 14 Tf <01> Tj 
10.1 0 Td <02> Tj               
9.3 0 Td <03> Tj
3.9 0 Td <01> Tj
10.1 0 Td <0405> Tj
18.7 0 Td <060607> Tj
21 0 Td <08090A07> Tj
24.9 0 Td <05> Tj
10.1 0 Td <0B0C0D> Tj
28.8 0 Td <0E> Tj
3.8 0 Td <0F> Tj
8.6 0 Td <090B1007> Tj
29.5 0 Td <0B11> Tj
16.4 0 Td <12> Tj
7.8 0 Td <1307> Tj
12.4 0 Td <14> Tj
7.8 0 Td <07> Tj
3.9 0 Td <15> Tj
7.8 0 Td <16> Tj
7.8 0 Td <07> Tj
3.9 0 Td <17> Tj
10.8 0 Td <0D> Tj
7.8 0 Td <18> Tj
10.9 0 Td <19> Tj
ET
.....

但是我不知道哪个字符串适合哪个位置 另一方面,在 Itext 中,我可以使用

获取纯文本
PdfReader reader = new PdfReader(new FileInputStream("/home/....xxx.pdf"));
PdfTextExtractor extract = new PdfTextExtractor(reader);

但当然没有任何位置......

那么我怎样才能得到每个 text(string,char,...) 的准确位置呢?

最佳答案

正如 plinth 和 David van Driessche 在他们的回答中指出的那样,从 PDF 文件中提取文本并非易事。幸运的是,iText 的解析器包中的类为您完成了大部分繁重的工作。您已经从那个包中找到了至少一个类,PdfTextExtractor,但是如果您只对页面的纯文本感兴趣,那么这个类本质上是一个使用 iText 解析器功能的便利实用程序。在您的情况下,您必须更深入地查看该包中的类。

获取有关使用 iText 提取文本主题的信息的起点是 iText in Action — 2nd Edition 的第 15.3 节解析 PDF ,尤其是样本 ParsingHelloWorld.java 的方法extractText :

public void extractText(String src, String dest) throws IOException
{
    PrintWriter out = new PrintWriter(new FileOutputStream(dest));
    PdfReader reader = new PdfReader(src);
    RenderListener listener = new MyTextRenderListener(out);
    PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
    PdfDictionary pageDic = reader.getPageN(1);
    PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);
    processor.processContent(ContentByteUtils.getContentBytesForPage(reader, 1), resourcesDic);
    out.flush();
    out.close();
}

它利用了 RenderListener 实现 MyTextRenderListener.java :

public class MyTextRenderListener implements RenderListener
{
    [...]

    /**
     * @see RenderListener#renderText(TextRenderInfo)
     */
    public void renderText(TextRenderInfo renderInfo) {
        out.print("<");
        out.print(renderInfo.getText());
        out.print(">");
    }
}

虽然此RenderListener 实现仅输出文本,但 TextRenderInfo它检查的对象提供了更多信息:

public LineSegment getBaseline();    // the baseline for the text (i.e. the line that the text 'sits' on)
public LineSegment getAscentLine();  // the ascentline for the text (i.e. the line that represents the topmost extent that a string of the current font could have)
public LineSegment getDescentLine(); // the descentline for the text (i.e. the line that represents the bottom most extent that a string of the current font could have)
public float getRise()             ; // the rise which  represents how far above the nominal baseline the text should be rendered

public String getText();             // the text to render
public int getTextRenderMode();      // the text render mode
public DocumentFont getFont();       // the font
public float getSingleSpaceWidth();  // the width, in user space units, of a single space character in the current font

public List<TextRenderInfo> getCharacterRenderInfos(); // details useful if a listener needs access to the position of each individual glyph in the text render operation

因此,如果您的RenderListener除了使用getText()检查文本外,还考虑了getBaseline()甚至getAscentLine ()getDescentLine()。您拥有可能需要的所有坐标。

PS:ParsingHelloWorld.extractText()中的代码有一个包装类,PdfReaderContentParser ,它允许您简单地编写以下给定的 PdfReader 阅读器, 一个 int 页面, 和一个 RenderListener renderListener:

PdfReaderContentParser parser = new PdfReaderContentParser(reader);
parser.processContent(page, renderListener);

关于java - 获取 PDF 中的确切字符串位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13632541/

相关文章:

java - 为什么 OpenJDK 发布的新 Java 8 镜像不再基于 Alpine,而是基于 Debian 10(Buster)?

java - 在 Java Swing 应用程序中创建在线帮助 - 使用 pdf 用户文档

python - Camelot python;OSError : exception: access violation writing 0x00000080

Android 以编程方式打印 PDF

macos - 使用并行和 mutool 拆分多个 PDF 文件

java - 将图像加载到 ImageView 中会导致 "I/Choreographer: Skipped 139 frames! The application may be doing too much work on its main thread."错误

java - System.getProperty (“java.class.path” ) 无法在 Web 应用程序中工作

java - 如何从图像转换为短字符串?

java - 在内核上编写基本的 java shell 或 GUI

c# - 如何释放/处置 Windows.Data.PdfDocument