【问题标题】:PDFBox (2.1.0): When printed from IE11, transparent text watermark has opaque backgroundPDFBox (2.1.0):从 IE11 打印时,透明文本水印背景不透明
【发布时间】:2016-10-26 16:35:55
【问题描述】:

我在 Java 8 Spring Boot 应用程序中使用 PDFBox 2.1.0-SNAPSHOT 在原本只有图像的 PDF 文档的每一页上添加透明文本水印。从视觉上看,它工作得很好,因为我可以通过任何阅读器和所有浏览器内联 PDF 查看器上的水印看到图像。

但是,当我从 IE 打印这些文档时,不透明的白色背景会覆盖文本后面的图像。水印文字依然是透明的,但是文字的边框是白色的。同样,从所有其他浏览器打印都可以正常工作。 (一定喜欢 IE。)

这是我用来将水印添加到每个页面的代码:

public void watermark(File pdfFile, OutputStream output) throws IOException {
    try (final InputStream sourceStream = new FileInputStream(pdfFile);
         final PDDocument document = PDDocument.load(sourceStream)) {

        for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
            PDPage currPage  = document.getPage(pageNumber);
            writeWatermarkOnPage(document, currPage);
        }
        document.save(output);
    }
}

private void writeWatermarkOnPage(PDDocument document, PDPage page) throws IOException {
    try (PDPageContentStream contentStream = new PDPageContentStream(
            document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {

        PDRectangle rect = page.getBBox();
        // Set the opacity
        PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
        extendedGraphicsState.setNonStrokingAlphaConstant(0.3f);
        contentStream.setGraphicsStateParameters(extendedGraphicsState);

        // Add the text
        contentStream.beginText();
        contentStream.setFont(PDType1Font.HELVETICA_BOLD, 75);
        contentStream.setNonStrokingColor(Color.GRAY);
        AffineTransform at = new AffineTransform(1, 0, 0, 1,
                                                 rect.getUpperRightX() / 4,
                                                 rect.getUpperRightY() / 4);
        Matrix matrix = new Matrix(at);
        matrix.rotate(Math.toRadians(45));
        contentStream.setTextMatrix(matrix);
        contentStream.showText("WATERMARK-TEXT");
        contentStream.endText();
    }
}

我尝试使用 Overlay 类,但结果相同。我尝试删除旋转和变换,但这没有帮助。只有当我删除 nonStrokingAlphaConstant 设置时,从 IE 的内联 PDF 渲染器打印时,不透明的白色背景才会消失,但文本不再透明。

我还需要做些什么来告诉每个上下文中的每个 PDF 阅读器文本的背景应该是完全透明的吗?

更新

这是一个示例PDF Document that shows this behavior。在 Windows 上,我只需将其拖放到 IE 中,打印它,水印文本的白色背景就会覆盖底层图像。

这是来自 IE 的另一个示例 PDF created and watermarked with the same code that actually prints just fine。水印是透明的,没有白色背景。

我认为不同之处在于损坏的文档是合法大小的图像,而工作文档是字母大小。也许与缩放有关的东西导致了这个问题?

【问题讨论】:

  • 1) 从 Adob​​e Reader 打印可以吗? 2) MSIE 中用于显示/打印 PDF 的程序是什么?
  • 是的,@Tilman,如果我从独立的 Adob​​e Reader DC 打印就可以了,这很奇怪。在 MSIE 中,它使用 Adob​​e Reader 来显示/打印 PDF。
  • 请分享一个可以观察到问题的示例 pdf。
  • @mkl,我在后期更新中添加了示例 PDF 文档和更多测试结果。
  • @Tilman 我刚刚发现了一个解决方法:如果我创建一个具有透明背景的 PNG 并用透明度覆盖它,它就可以正常工作并打印。如果没有办法使用文本,我可能会继续前进。完成后我会发布代码。

标签: java pdfbox


【解决方案1】:

我能够通过使用透明 PNG 作为水印而不是将其添加为文本来实现我的目标。新的水印文件现在可以从所有浏览器正确打印,包括 IE。这是我用来为 PDF 的每一页添加水印的代码:

private static final String WATERMARK_RESOURCE_PATH = "/watermark/hcro_copy.png";

public void watermark(File pdfFile, OutputStream output) throws IOException {
    try (final InputStream sourceStream = new FileInputStream(pdfFile);
         final PDDocument document = PDDocument.load(sourceStream)
    ) {
        for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
            PDPage currPage  = document.getPage(pageNumber);
            writeWatermarkWithTransparentImageOnPage(document, currPage);
        }
        document.save(output);
    }
}

private void writeWatermarkWithTransparentImageOnPage(PDDocument document, PDPage page)
        throws IOException {
    try (PDPageContentStream contentStream = new PDPageContentStream(
            document, page, PDPageContentStream.AppendMode.APPEND, true, true);
         InputStream watermarkFileStream = getWatermarkFileStream()
    ) {
        // Load watermark image
        BufferedImage image = ImageIO.read(watermarkFileStream);
        PDImageXObject pdxImage = LosslessFactory.createFromImage(document, image);

        // Set the opacity
        PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
        extendedGraphicsState.setNonStrokingAlphaConstant(0.35f);
        contentStream.setGraphicsStateParameters(extendedGraphicsState);

        // Center watermark image on page
        PDRectangle rect = page.getBBox();
        int imageX = Math.floorDiv((Math.round(rect.getWidth()) - pdxImage.getWidth()), 2);
        int imageY = Math.floorDiv((Math.round(rect.getHeight()) - pdxImage.getHeight()), 2);

        contentStream.drawImage(pdxImage, imageX, imageY);
    }
}

private InputStream getWatermarkFileStream() {
    try {
        Resource resource = new ClassPathResource(WATERMARK_RESOURCE_PATH);
        return resource.getInputStream();
    }
    catch (IOException e) {
        throw new RuntimeException(e);
    }
}

我仍然愿意接受纯文本的答案,但现在这对我有用。

【讨论】:

    猜你喜欢
    • 2021-07-03
    • 2017-01-19
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多