如何使用PDPageContentStream底层内容流?

时间:2015-02-13 14:52:50

标签: java pdfbox watermark

我正在尝试使用PDPageContentStream创建水印。这就是我现在所拥有的

PDPageContentStream contentStream = new PDPageContentStream(doc,page, true,true);
contentStream.beginText();
contentStream.setFont(font,40);
contentStream.setTextRotation(Math.PI/4,page.getMediaBox().getWidth()/4,page.getMediaBox().getHeight()/4);
contentStream.setNonStrokingColor(210,210,210); //light grey
contentStream.drawString(_text);
contentStream.endText();
contentStream.close();

它会产生一个45度角文本,浅灰色。但是 - 当然 - 它覆盖了它下面的实际页面内容,并且不可能看到一些内容。

是否可以先创建contentStream然后附加页面内容? 我找到了this示例。它使用PDExtendedGraphicsState和PDResources。我是pdfbox的新手,几乎没有图形经验。 这些是我需要的,pdfbox中的资源是什么?

提前致谢。

P.S。我知道我可以使用覆盖实用程序和jpeg。但我现在试图用PDPageContentStream来解决这个问题。

3 个答案:

答案 0 :(得分:1)

如果您使用PDFBox 2.0+,那么它现在稍微容易一些:

PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
extendedGraphicsState.setNonStrokingAlphaConstant((float) alpha);
contents.saveGraphicsState();
contents.setGraphicsStateParameters(extendedGraphicsState);
// do your stuff 
contents.restoreGraphicsState();

答案 1 :(得分:0)

我明白了。答案实际上是here。但是我不得不一点一点地走路。这是我的代码:

PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
// Set the transparency/opacity
extendedGraphicsState.setNonStrokingAlphaConstant(0.5f);
PDResources resources = page.findResources();// Get the page resources.
// Get the defined graphic states.
Map graphicsStateDictionary = resources.getGraphicsStates();

 if (graphicsStateDictionary != null){ 
     graphicsStateDictionary.put("TransparentState", extendedGraphicsState); 
     resources.setGraphicsStates(graphicsStateDictionary); 
    }
 PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true); 
 contentStream.appendRawCommands("/TransparentState gs\n");
 contentStream.setNonStrokingColor(210,210,210);

此代码段创建PDExtendedGraphicsState对象。我的理解是'资源'是某种字典,并且包含不同PD对象的属性,如PDPage或PDGraphics。

一开始没有“透明状态”等状态。我们用

创建它
 extendedGraphicsState.setNonStrokingAlphaConstant(0.5f);

然后我们将graphicsState对象命名为TransparentState。这就是我们在AppendRawCommands中使用它的方式。

这种解释可能不充分或错误。请留下您的意见。我很乐意更好地理解它。

答案 2 :(得分:0)

正如对OP自己的答案的评论中提到的那样,答案并不完全是他所要求的(如何建立现有的流),而是覆盖透明度。

因此,这里有一个答案,显示了人们如何能够完成最初的要求,为现有的流提供支持。

如何实际预先添加内容流

Underlaying本质上意味着将新内容预先添加到现有内容中,因为后面的内容涵盖了前者。

不幸的是,PDFBox类PDPageContentStream只提供构造函数追加替换所有内容流但没有 prepend 一个新的内容流。

可能会有点作弊:首先可以添加一个新流,将其填充,就像它被预先添加一样,最后重新排序流:

void transformPage(PDDocument document, PDPage page) throws IOException, COSVisitorException
{
    PDPageContentStream stream = new PDPageContentStream(document, page, true, true);
    // add any content to stream as if it was the first stream
    stream.close();

    COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS);
    if (contents instanceof COSStreamArray)
    {
        COSStreamArray contentsArray = (COSStreamArray) contents;
        COSArray newArray = new COSArray();
        newArray.add(contentsArray.get(contentsArray.getStreamCount() - 1));

        for (int i = 0; i < contentsArray.getStreamCount() - 1; i++)
        {
            newArray.add(contentsArray.get(i));
        }

        COSStreamArray newStreamArray = new COSStreamArray(newArray);
        page.getCOSDictionary().setItem(COSName.CONTENTS, newStreamArray);
    }
}

哪个更好,前置或附加透明度

答案是......这取决于。 ;)

一方面,使用透明度的解决方案通常比使用底层的解决方案更接近预期的外观:你在第一个用白色填充整个区域的内容下面,你不会看到底层内容的任何内容!

另一方面,有多个上下文禁止使用透明度,特别是在PDF / A变体的情况下。由于不允许在这种情况下覆盖透明度,因此要么必须使用非常细的线条进行覆盖,要么只是简单地进行覆盖。