IText 7:如何构建段落的文本和附件的混合?
IText 7: How to build a mix of text and attachments to the paragraph?
我想用itext7生成类似这样的pdf文档:
但是我找不到任何方法来实现它。
我在教程中看到的 无法将附件和文本放在一起。您只能将附件放在单独的页面上。
如果是 itext5,我喜欢这样:
PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification);
chunk.setAnnotation(anno);
paragrah.add(chunk);
所以我可以在一个段落中添加文本、注释,但是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());
然后,我们想要实现的是能够将自定义注释元素添加到布局 Document
流中。
在最好的情况下,代码将如下所示:
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);
}
}
渲染器实现有更多代码,但它只是在 layout
上定义占用区域并在 draw
上向页面添加注释。请注意,它并未涵盖所有情况(例如,没有足够的 space 来容纳注释),但这对于简单的案例和演示目的来说已经足够了。
private static class AnnotationRenderer extends AbstractRenderer implements ILeafElementRenderer {
private PdfAnnotation annotation;
public AnnotationRenderer(PdfAnnotation annotat) {
this.annotation = annotat;
}
@Override
public float getAscent() {
return annotation.getRectangle().toRectangle().getHeight();
}
@Override
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 void draw(DrawContext drawContext) {
super.draw(drawContext);
annotation.setRectangle(new PdfArray(occupiedArea.getBBox()));
drawContext.getDocument().getPage(occupiedArea.getPageNumber()).addAnnotation(annotation);
}
@Override
public IRenderer getNextRenderer() {
return new AnnotationRenderer(annotation);
}
}
请注意,该示例适用于当前 7.0.3-SNAPSHOT
版本。可能不适用于发布 7.0.2
版本,因为后来添加了 ILeafElementRenderer
接口,但如果确实需要,仍然可以将代码调整为 7.0.2
。
感谢@Alexey Subach 的回复,我用你的方法解决了我自己的问题。因为我用的是7.0.2-SNAPSHOT版本。所以在AnnotationRenderer中class做了一点改动:
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这些class对我来说不是很懂,我想我需要看看API来了解更多。
我想用itext7生成类似这样的pdf文档:
但是我找不到任何方法来实现它。
我在教程中看到的
PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification);
chunk.setAnnotation(anno);
paragrah.add(chunk);
所以我可以在一个段落中添加文本、注释,但是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());
然后,我们想要实现的是能够将自定义注释元素添加到布局 Document
流中。
在最好的情况下,代码将如下所示:
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);
}
}
渲染器实现有更多代码,但它只是在 layout
上定义占用区域并在 draw
上向页面添加注释。请注意,它并未涵盖所有情况(例如,没有足够的 space 来容纳注释),但这对于简单的案例和演示目的来说已经足够了。
private static class AnnotationRenderer extends AbstractRenderer implements ILeafElementRenderer {
private PdfAnnotation annotation;
public AnnotationRenderer(PdfAnnotation annotat) {
this.annotation = annotat;
}
@Override
public float getAscent() {
return annotation.getRectangle().toRectangle().getHeight();
}
@Override
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 void draw(DrawContext drawContext) {
super.draw(drawContext);
annotation.setRectangle(new PdfArray(occupiedArea.getBBox()));
drawContext.getDocument().getPage(occupiedArea.getPageNumber()).addAnnotation(annotation);
}
@Override
public IRenderer getNextRenderer() {
return new AnnotationRenderer(annotation);
}
}
请注意,该示例适用于当前 7.0.3-SNAPSHOT
版本。可能不适用于发布 7.0.2
版本,因为后来添加了 ILeafElementRenderer
接口,但如果确实需要,仍然可以将代码调整为 7.0.2
。
感谢@Alexey Subach 的回复,我用你的方法解决了我自己的问题。因为我用的是7.0.2-SNAPSHOT版本。所以在AnnotationRenderer中class做了一点改动:
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这些class对我来说不是很懂,我想我需要看看API来了解更多。