java - 背景图片itextpdf 5.5
问题描述
我使用的是 itextpdf 5.5,无法将其更改为 7。背景图像有问题。我有一份没有盖章的文档(文本和表格),我想给它加盖章。
这就是我下载现有文档的方式。
PdfReader pdfReader = new PdfReader("/doc.pdf");
PdfImportedPage page = writer.getImportedPage(pdfReader, 1);
PdfContentByte pcb = writer.getDirectContent();
pcb.addTemplate(page, 0,0);
这就是我下载邮票图像并将其添加到我的文档中的方式。
PdfContentByte canvas = writer.getDirectContentUnder();
URL resource = getClass().getResource(getStamp());
Image background = new Jpeg(resource);
background.scaleToFit(463F, 132F);
background.setAbsolutePosition(275F, 100F);
canvas.addImage(background);
但是当我下载我的文件时 - 我没有看到邮票。当我下载我的文档时,我尝试将 getDirectContent() 更改为 getDirectContentUnder() ,但这会导致相反的情况 - 我的图章不在后台。
我的第一个文档就是这样生成的。
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Document document = new Document(PageSize.A4);
try {
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
Paragraph title = new Paragraph(formatUtil.msg("my.header"), fontBold);
title.setAlignment(Element.ALIGN_CENTER);
document.add(title);
Template tmpl = fmConfig.getConfiguration().getTemplate("template.ftl");
Map<String, Object> params = new HashMap<>();
StringWriter writer = new StringWriter();
params.put("param", "param");
tmpl.process(params, writer);
document.add(new Paragraph(writer.toString(), fontCommon));
PdfPTable table = new PdfPTable(2);
document.add(table);
PdfContentByte canvas = writer.getDirectContentUnder();
Image background = new Jpeg(getClass().getResource("background.jpg"));
background.scaleAbsolute(PageSize.A4);
background.setAbsolutePosition(0,0);
canvas.addImage(background);
} finally {
if (document.isOpen()) {
document.close();
}
}
解决方案
在评论中很明显,任务是将一些内容(位图图像)添加到 PDF 中,以便它位于生成期间添加到原始文本中的背景(另一个位图图像)之上。UnderContent
DirectContent
iText 不包含用于此类内容操作的高级代码。虽然 iText 生成的 PDF 的结构允许此类代码,但由其他 PDF 库生成或操作的 PDF 可能具有不同的结构;iText 生成的 PDF 中的结构甚至可以在使用其他库进行后处理期间更改。因此,iText 没有为此提供高级功能是可以理解的。
尽管如此,为了实现该任务,我们必须将我们的代码基于较低级别的 iText API。在这种情况下,我们可以使用这个答案中的PdfContentStreamEditor
帮助类,它已经抽象了一些细节。(该问题最初是关于 C# 的 iTextSharp,但在答案的更下方,还提供了代码的 Java 版本。)
详细地说,我们扩展了PdfContentStreamEditor
以删除以前的 UnderContent(并将其作为指令列表提供)。现在我们可以在第一步中将此编辑器应用到您的文件中,然后在第二步中将这个以前的 UnderContent 加上它上面的图像添加到中间文件中。(这也可以一步完成,但这需要更复杂、更难维护的编辑器类。)
首先是新的UnderContentRemover
内容流编辑器类:
public class UnderContentRemover extends PdfContentStreamEditor {
/**
* Clears state of {@link UnderContentRemover}, in particular
* the collected content. Use this if you use this instance for
* multiple edit runs.
*/
public void clear() {
afterUnderContent = false;
underContent.clear();
depth = 0;
}
/**
* Retrieves the collected UnderContent instructions
*/
public List<List<PdfObject>> getUnderContent() {
return new ArrayList<List<PdfObject>>(underContent);
}
/**
* Adds the given instructions (which may previously have been
* retrieved using {@link #getUnderContent()}) to the given
* {@link PdfContentByte} instance.
*/
public static void write (PdfContentByte canvas, List<List<PdfObject>> operations) throws IOException {
for (List<PdfObject> operands : operations) {
int index = 0;
for (PdfObject object : operands) {
object.toPdf(canvas.getPdfWriter(), canvas.getInternalBuffer());
canvas.getInternalBuffer().append(operands.size() > ++index ? (byte) ' ' : (byte) '\n');
}
}
}
protected void write(PdfContentStreamProcessor processor, PdfLiteral operator, List<PdfObject> operands) throws IOException {
String operatorString = operator.toString();
if (afterUnderContent) {
super.write(processor, operator, operands);
return;
} else if ("q".equals(operatorString)) {
depth++;
} else if ("Q".equals(operatorString)) {
depth--;
if (depth < 1)
afterUnderContent = true;
} else if (depth == 0) {
afterUnderContent = true;
super.write(processor, operator, operands);
return;
}
underContent.add(new ArrayList<>(operands));
}
boolean afterUnderContent = false;
List<List<PdfObject>> underContent = new ArrayList<>();
int depth = 0;
}
如您所见,它的write
方法将转发给它的前导指令存储在underContent
列表中,直到找到与Q
初始保存图形状态指令(q
)匹配的恢复图形状态()指令。之后,它将所有进一步的指令转发给父write
实现,父实现将它们写入编辑的页面内容。
我们可以将其用于手头的任务,如下所示:
PdfReader pdfReader = new PdfReader(YOUR_DOCUMENT);
List<List<List<PdfObject>>> underContentByPage = new ArrayList<>();
byte[] sourceWithoutUnderContent = null;
try ( ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ) {
PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream);
UnderContentRemover underContentRemover = new UnderContentRemover();
for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
underContentRemover.clear();
underContentRemover.editPage(pdfStamper, i);
underContentByPage.add(underContentRemover.getUnderContent());
}
pdfStamper.close();
pdfReader.close();
sourceWithoutUnderContent = outputStream.toByteArray();
}
Image background = YOUR_IMAGE_TO_ADD_INBETWEEN;
background.scaleToFit(463F, 132F);
background.setAbsolutePosition(275F, 100F);
pdfReader = new PdfReader(sourceWithoutUnderContent);
byte[] sourceWithStampInbetween = null;
try ( ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ) {
PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream);
for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
PdfContentByte canvas = pdfStamper.getUnderContent(i);
UnderContentRemover.write(canvas, underContentByPage.get(i-1));
canvas.addImage(background);
}
pdfStamper.close();
pdfReader.close();
sourceWithStampInbetween = outputStream.toByteArray();
}
Files.write(new File("PdfLikeVladimirSafonov-WithStampInbetween.pdf").toPath(), sourceWithStampInbetween);
( AddImageInBetween测试testForVladimirSafonov
)
推荐阅读
- python - 如何将图像(多维数组)数据拟合到 python 中的随机森林分类器中?
- xaml - Xamarin XAML,如何将元组列表绑定到可绑定布局
- r - 使用 Datatables Selected_Row 时如何获取特定列值
- c# - Angular 9 前端/ASP.Net C# MVC 后端
- python - CNN 给出相同的损失和准确性
- c# - 如何将布尔值转换为字符串?
- git - git:撤消对本地存储库的所有更改并获取上游存储库的副本
- python - 与 python 烧瓶的动态链接引发错误
- hibernate - 带有鉴别器列的 JPA @Embeddable 继承
- elixir - 如何在 Phoenix 中定义一个使用 Poison 库的模块