Create a watermark (PDF Downloadable Content) that appears only when printing using PDFBox

I came across many examples that use the appendFormAsLayer method of the PDFBox Layer Utility, 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 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; } 

What is the meaning of β€œMC” in the getPDFName call in the previous code?

I wrote the following code to insert a watermark on each page of an existing pdf and include each additional 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); 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); } } 

Setting the group to enable or disable "setGroupEnabled (groupName, true)" makes it appear for both display and printing. According to other information that I investigated on this subject, you can fine-tune it when additional content is displayed, which indicates the existence of the onScreen and onPrint Boolean attributes, which can be set to determine the visibility of the content. See https://acrobatusers.com/tutorials/watermarking-a-pdf-with-javascript

Is there a way to use the PDFBox to make the watermark appear when printing, but not when displaying? If not, any suggestions for alternative solutions will be appreciated.

Here is additional code to create a pdf watermark from the line (createOverlay) and the function (addWatermark) that calls LayerUtility, which passes the watermark document. All that is required is to create a PDDocument from any existing pdf file and transfer it using a 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; } 
+5
source share

All Articles