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

时间:2016-10-26 16:35:56

标签: java pdfbox

我在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上,我只是拖动&amp;将其放入IE中,打印出来,水印文本的白色背景会覆盖底层图像。

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

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

1 个答案:

答案 0 :(得分:0)

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

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