Java PDFBox创建仅包含屏幕内容的PDF

Java PDFBox创建仅包含屏幕内容的PDF,java,pdf,pdfbox,Java,Pdf,Pdfbox,我想用Java创建一个PDF(我更喜欢在这里使用PDFBox,但这不是一个严格的要求)。必须删除部分内容 在屏幕上可见 但打印时,不可见 (把它想象成页眉,它已经预先打印在纸上,但是PDF的数字版本应该在屏幕上显示这个页眉,而不是打印它) 我看到了这篇文章,它展示了一个很好的内容示例,即仅打印但在屏幕上不可见: 现在我需要的正好相反:在屏幕上显示,但不要打印。我也试着阅读,但没有按照我的要求创建一个PDF(使用“视图”和事件“视图”以及“视图”和“打印”的组合……) PS:或者,一个满足要

我想用Java创建一个PDF(我更喜欢在这里使用PDFBox,但这不是一个严格的要求)。必须删除部分内容

  • 在屏幕上可见
  • 但打印时,不可见
(把它想象成页眉,它已经预先打印在纸上,但是PDF的数字版本应该在屏幕上显示这个页眉,而不是打印它)

我看到了这篇文章,它展示了一个很好的内容示例,即仅打印但在屏幕上不可见:

现在我需要的正好相反:在屏幕上显示,但不要打印。我也试着阅读,但没有按照我的要求创建一个PDF(使用“视图”和事件“视图”以及“视图”和“打印”的组合……)


PS:或者,一个满足要求的简单PDF(在屏幕上显示两个单词,打印时只打印其中一个单词)肯定会有帮助(并且可能足够),因为我认为我应该能够使用PDFBox重新创建必要的词典…

我自己设法找到了一个解决方案。基本上,我就是这么做的:

  • 在屏幕上绘制我想要的所有内容
  • 绘制一个白色矩形,即页面大小,仅在打印时可见
  • 在屏幕上和印刷品上画我想要的任何东西
  • 下面是一些代码:

    /**
     * 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();