创建仅在使用PDFBox打印时显示的水印(pdf可选内容) [英] Create a watermark (pdf Optional Content) that shows only when printing using PDFBox

查看:117
本文介绍了创建仅在使用PDFBox打印时显示的水印(pdf可选内容)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了许多使用PDFBox Layer Utility的appendFormAsLayer方法的示例,如下所示:

I have come across many examples that use the PDFBox Layer Utility's appendFormAsLayer method as shown below:

 /**
 * Places the given form over the existing content of the indicated page (like an overlay).
 * The form is enveloped in a marked content section to indicate that it's part of an
 * optional content group (OCG), here used as a layer. This optional group is returned and
 * can be enabled and disabled through methods on {@link PDOptionalContentProperties}.
 * @param targetPage the target page
 * @param form the form to place
 * @param transform the transformation matrix that controls the placement
 * @param layerName the name for the layer/OCG to produce
 * @return the optional content group that was generated for the form usage
 * @throws IOException if an I/O error occurs
 */
public PDOptionalContentGroup appendFormAsLayer(PDPage targetPage,
        PDXObjectForm form, AffineTransform transform,
        String layerName) throws IOException
{
    PDDocumentCatalog catalog = targetDoc.getDocumentCatalog();
    PDOptionalContentProperties ocprops = catalog.getOCProperties();
    if (ocprops == null)
    {
        ocprops = new PDOptionalContentProperties();
        catalog.setOCProperties(ocprops);
    }
    if (ocprops.hasGroup(layerName))
    {
        throw new IllegalArgumentException("Optional group (layer) already exists: " + layerName);
    }

    PDOptionalContentGroup layer = new PDOptionalContentGroup(layerName);
    ocprops.addGroup(layer);

    PDResources resources = targetPage.findResources();
    PDPropertyList props = resources.getProperties();
    if (props == null)
    {
        props = new PDPropertyList();
        resources.setProperties(props);
    }

    //Find first free resource name with the pattern "MC<index>"
    int index = 0;
    PDOptionalContentGroup ocg;
    COSName resourceName;
    do
    {
        resourceName = COSName.getPDFName("MC" + index);
        ocg = props.getOptionalContentGroup(resourceName);
        index++;
    } while (ocg != null);
    //Put mapping for our new layer/OCG
    props.putMapping(resourceName, layer);

    PDPageContentStream contentStream = new PDPageContentStream(
            targetDoc, targetPage, true, !DEBUG);
    contentStream.beginMarkedContentSequence(COSName.OC, resourceName);
    contentStream.drawXObject(form, transform);
    contentStream.endMarkedContentSequence();
    contentStream.close();

    return layer;
}

在先前代码的getPDFName调用中,"MC"的含义是什么?

What is the significance of "MC" in the getPDFName call in the previous code?

我编写了以下代码,将水印插入到现有pdf的每一页上,并启用每组可选内容.

I have written the following code to insert the watermark on each page of an existing pdf and enable each group of optional content.

    LayerUtility layerUtility = new LayerUtility(document);
    PDXObjectForm form = layerUtility.importPageAsForm(overlayDoc, 0);
    for (int i = 0; i < document.getDocumentCatalog().getAllPages().size(); i++) {
        PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(i);
        PDOptionalContentGroup ocGroup = layerUtility.appendFormAsLayer(page, form, new AffineTransform(), "watermark" + i);
    }



    PDOptionalContentProperties ocprops = document.getDocumentCatalog().getOCProperties();

    for (String groupName : ocprops.getGroupNames()) {
        if (groupName.startsWith("watermark")) {
            ocprops.setGroupEnabled(groupName, true);
        }
    }

将组设置为启用或禁用的"setGroupEnabled(groupName,true)"会使它同时显示以进行显示和打印.根据我对此主题研究的其他信息,可以在可见可选内容时进行更精细的调整,这表明可以设置onScreen和onPrint布尔属性来确定内容的可见性.参见 https://acrobatusers.com/tutorials/watermarking-a-pdf-with-javascript

Setting the group to enabled or disabled "setGroupEnabled(groupName, true)" causes it to show for both displaying and printing. According to other information I have researched on this subject it is possible to more finely tune when optional content is visible, which indicates the existence of onScreen and onPrint Boolean attributes that can be set to determine the visibility of the content. See https://acrobatusers.com/tutorials/watermarking-a-pdf-with-javascript

是否有一种使用PDFBox的方法使水印在打印时可见,而在显示时不可见?如果没有,将对替代解决方案的任何建议表示赞赏.

Is there a way using PDFBox to cause a watermark to be visible when printed but not when displayed? If not, any suggestions of alternate solutions would be appreciated.

这是从字符串(createOverlay)和一个函数(addWatermark)创建水印pdf的附加代码,该函数调用传递水印文档的LayerUtility.所需要做的就是从任何现有的pdf文件创建PDDocument,并将其与水印字符串一起传递.

Here is additional code to create a watermark pdf from a string (createOverlay) and a function (addWatermark) that calls the LayerUtility passing the watermark document. All that is required is to create a PDDocument from any existing pdf file and pass it with the watermark string.

public PDDocument addWatermark(PDDocument document, String text) throws IOException {
    PDDocument overlayDoc = createOverlay(text);
    //  Create the watermark in an optional content group
    LayerUtility layerUtility = new LayerUtility(document);
    PDXObjectForm form = layerUtility.importPageAsForm(overlayDoc, 0);
    for (int i = 0; i < document.getDocumentCatalog().getAllPages().size(); i++) {
        PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(i);
        layerUtility.appendFormAsLayer(page, form, new AffineTransform(), "watermark" + i);
    }
    return document;        
}

private PDDocument createOverlay(String text) throws IOException {
    // Create a document and add a page to it
    PDDocument document = new PDDocument();
    PDPage page = new PDPage();
    document.addPage(page);

    PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
     // Set the transparency/opacity
     extendedGraphicsState.setNonStrokingAlphaConstant(0.4f);
     if (page.findResources() == null) {
         page.setResources(new PDResources());
     }
     PDResources resources = page.findResources();// Get the page resources.
     // Get the defined graphic states.
     if (resources.getGraphicsStates() == null)
     {
         resources.setGraphicsStates(new HashMap<String, PDExtendedGraphicsState>());
     }
     Map<String, PDExtendedGraphicsState> graphicsStateDictionary = resources.getGraphicsStates();

      if (graphicsStateDictionary != null){ 
          graphicsStateDictionary.put("TransparentState", extendedGraphicsState); 
          resources.setGraphicsStates(graphicsStateDictionary); 
     }

    // the x/y coords
    Float xVal = 0f; //Float.parseFloat(config.getProperty("ss.xVal"));
    Float yVal = 0f; //Float.parseFloat(config.getProperty("ss.yVal"));

    // Start a new content stream which will "hold" the to be created content
    PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);
      contentStream.appendRawCommands("/TransparentState gs\n");

    // Create the text and position it
    contentStream.beginText();
    contentStream.setFont(font, fontSize);
    contentStream.setTextRotation(Math.PI/4,page.getMediaBox().getWidth()/4,page.getMediaBox().getHeight()/4);
    contentStream.setNonStrokingColor(210,210,210); //light grey
    contentStream.moveTextPositionByAmount(xVal, yVal);
    contentStream.drawString(text);
    contentStream.endText();

    // Make sure that the content stream is closed:
    contentStream.close();

    //return the string doc
    return document;
}

推荐答案

private void addWaterMark(PDDocument document) throws Exception
{
    PDDocumentCatalog catalog = document.getDocumentCatalog();
    PDOptionalContentProperties ocprops = catalog.getOCProperties();
    if (ocprops == null)
    {
        ocprops = new PDOptionalContentProperties();
        ocprops.setBaseState(BaseState.OFF);
        catalog.setOCProperties(ocprops);
    }
    String layerName = "conWatermark";
    PDOptionalContentGroup watermark = null;
    if (ocprops.hasGroup(layerName))
    {
        watermark = ocprops.getGroup(layerName);
    }
    else
    {
        watermark = new PDOptionalContentGroup(layerName);
        ocprops.addGroup(watermark);
    }

    COSDictionary watermarkDic = watermark.getCOSObject();
    COSDictionary printState = new COSDictionary();
    printState.setItem("PrintState", COSName.ON);
    COSDictionary print = new COSDictionary();
    print.setItem("Print", printState);
    watermarkDic.setItem("Usage", print);

    COSDictionary asPrint = new COSDictionary();
    asPrint.setItem("Event", COSName.getPDFName("Print"));
    COSArray category = new COSArray();
    category.add(COSName.getPDFName("Print"));
    asPrint.setItem("Category", category);
    COSArray ocgs = new COSArray();
    ocgs.add(watermarkDic);
    asPrint.setItem(COSName.OCGS, ocgs);
    COSArray as = new COSArray();
    as.add(asPrint);
    COSDictionary d = (COSDictionary) ((COSDictionary) ocprops.getCOSObject()).getDictionaryObject(COSName.D);
    d.setItem(COSName.AS, as);

    for (int n = 0; n < document.getNumberOfPages(); n++)
    {
        PDPage page = document.getPage(n);

        PDResources resources = page.getResources();
        if (resources == null)
        {
            resources = new PDResources();
            page.setResources(resources);
        }

        String text1 = "Confidential";
        String text2 = "Document ..."; //

        PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
        graphicsState.setNonStrokingAlphaConstant(0.08f);

        PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);
        contentStream.setGraphicsStateParameters(graphicsState);
        contentStream.setNonStrokingColor(Color.GRAY);

        contentStream.beginMarkedContent(COSName.OC, watermark);

        contentStream.beginText();

        PDRectangle pageSize = page.getBBox();
        float fontSize = this.getFittingFontSize(pageSize, text1);
        PDFont font = this.WATERMARK_FONT;
        contentStream.setFont(font, fontSize);
        float text1Width = this.getTextWidth(font, fontSize, text1);
        float rotation = (float) Math.atan(pageSize.getHeight() / pageSize.getWidth());
        Point p = this.getStartPoint(pageSize, fontSize, text1);
        AffineTransform at = new AffineTransform(1, 0, 0, 1, p.getX(), p.getY());
        at.rotate(rotation);
        Matrix matrix = new Matrix(at);
        contentStream.setTextMatrix(matrix);
        contentStream.showText(text1);

        fontSize = this.getFittingFontSize(pageSize, text2);
        contentStream.setFont(font, fontSize);
        contentStream.newLineAtOffset(-(this.getTextWidth(font, fontSize, text2) - text1Width) / 2, -fontSize * 1.2f);
        contentStream.showText(text2);
        contentStream.endMarkedContent();
        contentStream.endText();
        contentStream.close();
    }
}

这篇关于创建仅在使用PDFBox打印时显示的水印(pdf可选内容)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆