当前位置: 首页 > 知识库问答 >
问题:

如何使用PDPageContentStream为内容流添加基线?

逑兴安
2023-03-14

我正在尝试使用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,然后附加页面内容?我找到了这个例子。它使用PDExtendedGraphicsState和PDResources。我是pdfbox的新手,几乎没有图形方面的经验。这些是我需要的吗?什么是pdfbox中的资源?

提前谢谢。

p、 我知道我可以将叠加实用程序与jpeg一起使用。但我现在正试图用PDPageContentStream解决这个问题。

共有3个答案

蒋培
2023-03-14

正如在对OP自己答案的评论中所提到的,这个答案并不完全是他所要求的(如何在现有的溪流之下),而是覆盖了透明度。

因此,这里有一个答案,显示了如何在现有流的基础上完成最初的要求。

基线基本上意味着将新内容预先添加到现有内容中,因为后者覆盖了前者。

不幸的是,PDFBox类PDPageContentStream只提供构造函数来追加或替换所有内容,而没有提供任何构造函数来预先追加新内容流。

不过,也有可能会有点作弊:可以先附加一个新流,将其填充为预先设置好的流,最后对流重新排序:

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变体的情况下。由于在这种情况下不允许使用透明覆盖,因此只能使用非常细的线进行覆盖,或仅使用参考底图进行覆盖。

琴献
2023-03-14

我想通了。答案实际上在这里。但是我不得不绕着它走一会儿。这是我的代码:

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

然后我们将graph icsState对象命名为TransparentState。这就是我们在AppendRawCommand ds中使用它的方式。

这个解释可能不够充分或错误。请留下你的评论。我很乐意更好地理解它。

倪举
2023-03-14

如果您使用PDFBox 2.0,那么现在就更容易了:

PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
extendedGraphicsState.setNonStrokingAlphaConstant((float) alpha);
contents.saveGraphicsState();
contents.setGraphicsStateParameters(extendedGraphicsState);
// do your stuff 
contents.restoreGraphicsState();
 类似资料:
  • 我正在使用pdfbox 2.0.8-需要创建一个层,并在那里添加一些图形。 我从如何修改pdf中的现有层(可选内容组)开始? 然而,这是基于1.8。我试图适应2.0,并设法创建了该层,但完全不清楚如何创建新资源并将其添加到该层,即如何创建道具。putMapping(resourceName,layer);必须重写1.8中的内容

  • 问题内容: 如何使用 CSS 属性添加 HTML 实体? 使用这样的东西只会打印到屏幕上,而不是不间断的空间: 问题答案: 您必须使用转义的unicode: 喜欢

  • 问题内容: 使用CMS,可防止编辑元素的HTML源。 例如,我想在标签上方添加以下内容: 问题答案: 您可以选择它并正常添加到它:

  • 我在React应用程序中使用: 我想在最后一列标题中添加一些按钮(而不是列名): 其中列: 那要怎么做?有可能吗?我什么都找不到

  • 我想使用javascript访问一个网站。但我在控制台中遇到以下错误。 拒绝连接到'https://example.com'因为它违反了以下内容安全策略指令:“default src'self'”。请注意,未显式设置“connect src”,因此使用“default src”作为回退。 我在index.html中添加了以下meta标记, 元超文本传输协议-Equiv="内容-安全-策略"内容="