PDFBox (2.1.0):从IE11打印时,透明文本水印背景不透明

PDFBox (2.1.0): When printed from IE11, transparent text watermark has opaque background

我在 Java 8 Spring 启动应用程序中使用 PDFBox 2.1.0-SNAPSHOT,以便在纯图像 PDF 文档的每一页上添加透明文本水印。在视觉上,它工作正常,因为我能够通过任何 reader 和所有浏览器内联 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();
    }
}

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

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

更新

这里有一个例子PDF Document that shows this behavior。在 Windows 上,我只需将其拖放到 IE 中,然后打印它,水印文本的白色背景就会覆盖下面的图像。

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

我认为不同之处在于损坏的文档是合法尺寸的图像,而工作文档是信纸尺寸。也许与缩放相关的问题是导致问题的原因?

通过使用透明 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);
    }
}

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