iPirat
iPirat

Reputation: 2206

PDFBox create PDF with screen-only content

I would like to create a PDF in Java (I'd prefer to use PDFBox here, but isn't a strict requirement). A part of the content must be

(Think of it like header, which is already pre-printed on paper, but the digital version of the PDF should show this header on screen, but not print it)

I came across this post, which shows a nice example of content, that is print-only but invisible on the screen: Create a watermark (pdf Optional Content) that shows only when printing using PDFBox

Now I need the exact opposite: show on screen but don't print. I also tried reading chapter 8.11 of PDF-1.7 spec, but didn't manage to create a PDF with my requirements (played around with Usage "View" and Event "View" and combinations of "View" and "Print"...)

PS: Alternatively, a simple PDF that fulfills the requirements (showing 2 words on screen, only one of which is printed when printed) would definitely help (and probably suffice), as I think I should be able to recreate the necessary dictionaries using PDFBox...

Upvotes: 1

Views: 468

Answers (1)

iPirat
iPirat

Reputation: 2206

I managed to find a solution myself. Basically, this is what I did:

  1. Draw everything I only want on screen
  2. Draw a white rectangle, the size of the page, that is only visible when printing
  3. Draw whatever I wanted to be on Screen AND on the print.

Here some code:

/**
 * adds a group (aka Layer) to PDF document that is only visible when printing
 * 
 * @param document
 * @throws IOException
 */
private static void addPrintOnlyLayer(PDDocument document) throws IOException {
    /* kinda constants */
    COSName printName = COSName.getPDFName("Print");
    COSArray printCategory = new COSArray();
    printCategory.add(printName);
    COSDictionary printState = new COSDictionary();
    printState.setItem("PrintState", COSName.ON);
    /* kinda constants */

    PDDocumentCatalog catalog = document.getDocumentCatalog();
    PDOptionalContentProperties ocProps = catalog.getOCProperties();
    if (ocProps == null) {
        ocProps = new PDOptionalContentProperties();
        ocProps.setBaseState(BaseState.OFF);
        catalog.setOCProperties(ocProps);
    }

    COSDictionary ocPropsDict = (COSDictionary) ocProps.getCOSObject();
    COSDictionary dDict = ocPropsDict.getCOSDictionary(COSName.D);
    dDict.setItem(COSName.AS, new COSArray());

    PDOptionalContentGroup printOnlyGroup = null;
    if (ocProps.hasGroup(PRINT_ONLY_GROUP_NAME)) {
        printOnlyGroup = ocProps.getGroup(PRINT_ONLY_GROUP_NAME);
    } else {
        printOnlyGroup = new PDOptionalContentGroup(PRINT_ONLY_GROUP_NAME);
        ocProps.addGroup(printOnlyGroup);
    }

    COSDictionary printOnlyGroupDict = printOnlyGroup.getCOSObject();
    COSArray ocgs = new COSArray();
    ocgs.add(printOnlyGroupDict);

    COSDictionary usageDict = new COSDictionary();
    usageDict.setItem("Print", printState);

    printOnlyGroupDict.setItem("Usage", usageDict);

    COSDictionary asPrint = new COSDictionary();
    asPrint.setItem("Event", printName);
    asPrint.setItem("Category", printCategory);
    asPrint.setItem(COSName.OCGS, ocgs);

    dDict.getCOSArray(COSName.AS).add(asPrint);
}

/*** somewhere else ***/
PDDocument pdDoc = new PDDocument();
pdDoc.setVersion(1.7f);
addPrintOnlyLayer(pdDoc);
PDPage page = new PDPage(new PDRectangle(1000,2000));
pdDoc.addPage(page);

PDPageContentStream content = new PDPageContentStream(pdDoc, page);

/* add content that will only visible on screen */
content.set...
content.add...

/* add white rectangle covering everything that we had so far */        
content.beginMarkedContent(COSName.OC, pdDoc.getDocumentCatalog().getOCProperties().getGroup(PRINT_ONLY_GROUP_NAME));
// TODO: maybe get rect size from page dimensions dynamically
content.setNonStrokingColor(Color.WHITE);
content.addRect(0,0,1000,2000);// here, I know the size of my page
content.fill();
/* here, we could add more content that is visible ONLY on printer but NOT on screen */
content.endMarkedContent();

/* stroke around the page, so printing on larger paper will have a border */
/* drop later */
content.addRect(0,0,1000,2000);
content.stroke();

/* now add content that will be visible on the print out AND screen */
content.set...;
content.add...;

/* close content of page */
content.close();

Upvotes: 1

Related Questions