首页 > 解决方案 > 背景图片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();
            }
        }

标签: javaitext

解决方案


在评论中很明显,任务是将一些内容(位图图像​​)添加到 PDF 中,以便它位于生成期间添加到原始文本中背景(另一个位图图像)之上UnderContentDirectContent

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;
}

( UnderContentRemover )

如您所见,它的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)


推荐阅读