当前位置: 首页 > 知识库问答 >
问题:

将图像置于文本之上,通过使用PDFBox在PDF中使用文本位置。

楚知
2023-03-14

结果是图像没有正确放置在文本上。我把文本位置弄错了吗?

这是一个关于如何获取PDF中每个字符的x/y坐标和大小的示例

public class MyClass extends PDFTextStripper {

    pdocument = PDDocument.load(new File(fileName));

    stripper = new GetCharLocationAndSize();
    stripper.setSortByPosition(true);
    stripper.setStartPage(0);
    stripper.setEndPage(pdocument.getNumberOfPages());
    Writer dummy = new OutputStreamWriter(new 
    ByteArrayOutputStream());
    stripper.writeText(pdocument, dummy);


 /*
 * Override the default functionality of PDFTextStripper.writeString()
 */
@Override
protected void WriteString(String string, List<TextPosition> 
textPositions) throws IOException {

     String imagePath = "image.jpg";
     PDImageXObject pdImage = 
     PDImageXObject.createFromFile(imagePath,pdocument);

     PDPageContentStream contentStream = new 
     PDPageContentStream(pdocument, stripper.getCurrentPage(), true, 
     true);

     for (TextPosition text : textPositions) {

         if (text.getUnicode().equals("a")) {
         contentStream.drawImage(pdImage, text.getXDirAdj(), 
         text.getYDirAdj(), text.getWidthDirAdj(),text.getHeightDir()); 
       }
       }
    contentStream.close();
    pdocument.save("newdoc.pdf");
    }
    }

共有1个答案

白腾
2023-03-14

您可以使用text.getXDirAdj()text.getYDirAdj()作为内容流中的x和y坐标。这是行不通的,因为PDFBox在文本提取过程中使用的坐标被转换为他们更喜欢的用于文本提取的坐标系,参见JavaDocs:

/**
 * This will get the text direction adjusted x position of the character.
 * This is adjusted based on text direction so that the first character
 * in that direction is in the upper left at 0,0.
 *
 * @return The x coordinate of the text.
 */
public float getXDirAdj()

/**
 * This will get the y position of the text, adjusted so that 0,0 is upper left and it is
 * adjusted based on the text direction.
 *
 * @return The adjusted y coordinate of the character.
 */
public float getYDirAdj()

对于文本位置,您应该使用

text.getTextMatrix().getTranslatex()

text.getTextMatrix().getTranslateY()

但是,即使是这些数字也可能需要更正,参见这个答案,因为PDFBox将矩阵乘以一个平移,使裁剪框的左下角成为原点。

因此,如果PDRectanger cropBox是当前页面的裁剪框,则使用

text.getTextMatrix().getTranslatex() + cropBox.getLowerLeftX()

text.getTextMatrix().getTranslateY() + cropBox.getLowerLeftY()

(PDFBox的这种坐标标准化对于任何真正想要使用文本坐标的人来说都是一个PITA…)

您的代码还存在一些其他问题,其中一个问题在您共享的文档中变得清晰:在不重置图形上下文的情况下附加到页面内容流:

PDPageContentStream contentStream = new PDPageContentStream(pdocument,
        stripper.getCurrentPage(), true, true);

具有此签名的构造函数假定您不想重置上下文。使用带有附加布尔参数的参数,并将其设置为请求上下文重置:

PDPageContentStream contentStream = new PDPageContentStream(pdocument,
        stripper.getCurrentPage(), true, true, true);

现在,上下文被重置,位置再次正常。

不过,这两个构造函数都不推荐使用,因此不应使用。在开发部门,它们已经被移除。而是使用

PDPageContentStream contentStream = new PDPageContentStream(pdocument,
        stripper.getCurrentPage(), AppendMode.APPEND, true, true);

不过,这带来了另一个问题:为每个writeString调用创建一个新的PDPageContentStream。如果每次都通过上下文重置完成,则saveGraphicsState/restoreGraphicsState对的嵌套可能会变得相当深。因此,每个页面只应创建一个这样的内容流,并在该页面的所有writeString调用中使用它。

因此,文本剥离器子类可能如下所示:

class CoverCharByImage extends PDFTextStripper {
    public CoverCharByImage(PDImageXObject pdImage) throws IOException {
        super();
        this.pdImage = pdImage;
    }

    final PDImageXObject pdImage;
    PDPageContentStream contentStream = null;

    @Override
    public void processPage(PDPage page) throws IOException {
        super.processPage(page);
        if (contentStream != null) {
            contentStream.close();
            contentStream = null;
        }
    }

    @Override
    protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
        if (contentStream == null)
            contentStream = new PDPageContentStream(document, getCurrentPage(), AppendMode.APPEND, true, true);

        PDRectangle cropBox = getCurrentPage().getCropBox();

        for (TextPosition text : textPositions) {
            if (text.getUnicode().equals("a")) {
                contentStream.drawImage(pdImage, text.getTextMatrix().getTranslateX() + cropBox.getLowerLeftX(),
                        text.getTextMatrix().getTranslateY() + cropBox.getLowerLeftY(),
                        text.getWidthDirAdj(), text.getHeightDir());
            }
        }
    }
}

(CoverCharacterByImage内部类)

它可以这样使用:

PDDocument pdocument = PDDocument.load(...);

String imagePath = ...;
PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, pdocument);

CoverCharByImage stripper = new CoverCharByImage(pdImage);
stripper.setSortByPosition(true);
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
stripper.writeText(pdocument, dummy);
pdocument.save(...);

(CoverCharacterByImage测试testCoverLikeLez

导致了

 类似资料:
  • 问题内容: 当我有坐标时,pdfbox是否提供一些实用工具来突出显示文本? 文本的界限是已知的。 我知道还有其他库提供相同的功能,例如pdfclown等。但是pdfbox是否提供类似的功能? 问题答案: 好吧,我发现了这一点。很简单。

  • 有人能给我举个例子,说明如何使用ApachePDFBox转换不同图像中的PDF文件(PDF的每一页对应一个图像)?

  • 我已经设法使用Apache的Javafx和PDFbox将文本放入pdf文件中。现在,我正在尝试将拍摄场景屏幕截图的图像放入pdf文档中。 当我使用InputStream和OutputStream类时,会创建文档,但当我打开文档时,Adobe和其他程序会给我一个错误,说Acrobat无法正确显示页面。当我使用上面代码中注释掉的BuffereImage类时,文档很简单,没有创建,我不知道为什么。 笔记

  • 我需要帮助来实现PDF文档中文本和图像对象之间的映射。 如第一幅图所示,我的PDF文档中有3幅图像沿y方向随机排列。在它们的左边是文本。文本沿着图像的高度延伸。 我的目标是将文本合并到“ImObj”对象中(请参见ImObj类)。 第2张图显示,我想使用图像的高度来检测文本的位置(图像高度之外的所有文本都应忽略),在示例中,将有3个由3个图像形成的ImObj-对象。 pdf文件的链接位于此处(在We

  • 系统中的一些PDF文档是通过扫描创建的,其中包括OCR文本。然而,OCR没有正确执行(西里尔语和拉丁语字符混淆),尽管文档看起来可以搜索,但该信息完全不正确,无法使用。 在Adobe Acrobat Reader DC(或GoogleChrome)中查看PDF文档时,它会正确显示,但在使用PDF. js呈现文档的网页上,OCR文本会显示在前面,而不是原始文本的扫描图形呈现。 这个想法是通过从PDF

  • 背景 我一直在开发一个程序,它可以获取一个pdf,突出显示一些单词(通过pdfbox标记注释)并保存新的pdf。 为此,我扩展了PDFTextStripper类,以覆盖writeString()方法并获取每个单词(框)的TextPositions,这样我就可以准确地知道文本在PDF文档中的坐标位置(TextPosition对象为我提供每个单词框的坐标)。然后,在此基础上,我画了一个矩形,突出显示我