Java IText 7:如何混合文本和段落附件?

Java IText 7:如何混合文本和段落附件?,java,itext7,Java,Itext7,我想使用itext7生成类似以下pdf文档的内容: 但我找不到任何方法来实现这一点。 我在教程中看到的内容无法将附件和文本放在一起。您只能将附件放在单独的页面上。 如果是itext5,我喜欢这样: PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification); chunk.setAnnotation(anno); paragrah.add(chu

我想使用itext7生成类似以下pdf文档的内容:

但我找不到任何方法来实现这一点。 我在教程中看到的内容无法将附件和文本放在一起。您只能将附件放在单独的页面上。 如果是itext5,我喜欢这样:

PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification);
chunk.setAnnotation(anno);
paragrah.add(chunk);
Document document = new Document(pdfDoc);
Paragraph p = new Paragraph("There are two").add(new AnnotationElement(attachment)).add(new Text("elements"));
document.add(p);
document.close();
因此,我可以在一个段落中添加文本、注释,但itext7教程就是这样:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));
    Rectangle rect = new Rectangle(36, 700, 100, 100);
    PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdfDoc, PATH, null, "test.docx", null, null, false);
    PdfAnnotation attachment = new PdfFileAttachmentAnnotation(rect, fs)
            .setContents("Click me");

    PdfFormXObject xObject = new PdfFormXObject(rect);
    ImageData imageData = ImageDataFactory.create(IMG);
    PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
    canvas.addImage(imageData, rect, true);
    attachment.setNormalAppearance(xObject.getPdfObject());

    pdfDoc.addNewPage().addAnnotation(attachment);
    pdfDoc.close();

有人能帮我吗?

如果我理解正确,您希望在文档流的其他布局元素中添加注释

目前在
iText7
中没有快速实现它的方法(如
iText5
中的
setAnnotation
方法)。但是,
iText7
足够灵活,允许您创建自定义元素,而不必深入挖掘代码

初始部分与当前示例中的相同。此处正在设置注释本身:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));
Rectangle rect = new Rectangle(36, 700, 50, 50);
PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdfDoc, PATH, null, "test.docx", null, null, false);
PdfAnnotation attachment = new PdfFileAttachmentAnnotation(rect, fs)
        .setContents("Click me");

PdfFormXObject xObject = new PdfFormXObject(rect);
ImageData imageData = ImageDataFactory.create(IMG);
PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
canvas.addImage(imageData, rect, true);
attachment.setNormalAppearance(xObject.getPdfObject());
然后,我们想要实现的是能够将自定义注释元素添加到布局
文档
流中。 在最佳情况下,代码如下所示:

PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification);
chunk.setAnnotation(anno);
paragrah.add(chunk);
Document document = new Document(pdfDoc);
Paragraph p = new Paragraph("There are two").add(new AnnotationElement(attachment)).add(new Text("elements"));
document.add(p);
document.close();
现在我们只剩下定义
AnnotationElement
和相应的渲染器。元素本身没有任何特定的逻辑,除了创建自定义渲染器并向其传递注释外:

private static class AnnotationElement extends AbstractElement<AnnotationElement> implements ILeafElement {
    private PdfAnnotation annotation;

    public AnnotationElement(PdfAnnotation annotation) {
        this.annotation = annotation;
    }

    @Override
    protected IRenderer makeNewRenderer() {
        return new AnnotationRenderer(annotation);
    }
}

请注意,该示例适用于当前的
7.0.3-SNAPSHOT
版本。由于后来添加了
ILeafElementRenderer
接口,因此该版本可能不适用于
7.0.2
版本,但如果确实需要,仍然可以将代码改编为
7.0.2

感谢您的回复@Alexey Subach,通过使用您的方法,我解决了自己的问题。因为我使用的是7.0.2-SNAPSHOT版本。因此,在AnnotationRenderer类中做了一些更改:

public class AnnotationRenderer extends AbstractRenderer implements IRenderer {

  private PdfAnnotation annotation;

  public AnnotationRenderer(PdfAnnotation annotation) {
    this.annotation = annotation;
  }

  public float getAscent(){
    return annotation.getRectangle().toRectangle().getHeight();
  }

  public float getDescent(){
    return 0;
  }

  @Override
  public LayoutResult layout(LayoutContext layoutContext) {
    occupiedArea = layoutContext.getArea().clone();

    float myHeight = annotation.getRectangle().toRectangle().getHeight();
    float myWidth = annotation.getRectangle().toRectangle().getWidth();
    occupiedArea.getBBox().moveUp(occupiedArea.getBBox().getHeight() - myHeight).setHeight(myHeight);
    occupiedArea.getBBox().setWidth(myWidth);

    return new LayoutResult(LayoutResult.FULL, occupiedArea, null, null);
  }

  @Override
  public IRenderer getNextRenderer() {
    return new AnnotationRenderer(annotation);
  }

  @Override
  public void draw(DrawContext drawContext) {
      super.draw(drawContext);
    annotation.setRectangle(new PdfArray(occupiedArea.getBBox()));
    drawContext.getDocument().getPage(occupiedArea.getPageNumber()).addAnnotation(annotation);
}
}


我刚接触了itext不久,刚遇到这个问题的时候我觉得自己可能无法解决,但幸运的是得到了您的帮助。事实上,LayoutContext、occupiedArea、LayoutResult这些类对我来说并不理解,我想我需要看看API来了解更多。

您可能想尝试将这些类包括在itext代码库中。不过,我想知道,
occupiedArea
坐标是否总是以默认用户坐标系给出?例如,如果书写方向旋转…Hi@mkl。你是说RTL文本吗?在RTL文本的情况下,占用区域是相同的,但是标志符号的重新排序发生了,因此它只涉及要打印的标志符号的正确顺序,但是占用区域坐标遵循相同的逻辑,对于LTR情况。或者你指的是变换矩阵之类的东西?“或者你指的是变换矩阵之类的东西?”-是的,这就是我所想的。在iText 5中,有用于在表单元格上方创建注释的表事件侦听器,这些侦听器在具有旋转的表单元格中都失败,因为旋转是使用ctm更改实现的。我想知道您的
AnnotationRenderer
是否存在类似问题。顺便说一句,尽管在mkl,我没有被告知你的评论;可能是mkl使机制失效后的dot。请不要将您的解决方案添加到问题正文中,而是将其作为答案发布。