PDFBox 创建包含 screen-only 内容的 PDF
PDFBox create PDF with screen-only content
我想在 Java 中创建一个 PDF(我更愿意在这里使用 PDFBox,但这不是严格要求)。部分内容必须
- 可见on-screen
- 但打印时不可见。
(把它想象成 header,它在纸上已经 pre-printed,但是 PDF 的数字版本应该在屏幕上显示这个 header,而不是打印它)
我遇到了这个 post,它显示了一个很好的内容示例,即 print-only 但在屏幕上不可见:
Create a watermark (pdf Optional Content) that shows only when printing using PDFBox
现在我需要完全相反的方法:在屏幕上显示但不打印。我也尝试阅读 chapter 8.11 of PDF-1.7 spec,但未能按照我的要求创建 PDF(使用 Usage "View" 和 Event "View" 以及 "View" 和 [= 的组合) 38=]...)
PS:或者,满足要求的简单 PDF(在屏幕上显示 2 个单词,打印时只打印其中一个)肯定会有所帮助(可能 足够了),因为我认为我应该能够使用 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();
我想在 Java 中创建一个 PDF(我更愿意在这里使用 PDFBox,但这不是严格要求)。部分内容必须
- 可见on-screen
- 但打印时不可见。
(把它想象成 header,它在纸上已经 pre-printed,但是 PDF 的数字版本应该在屏幕上显示这个 header,而不是打印它)
我遇到了这个 post,它显示了一个很好的内容示例,即 print-only 但在屏幕上不可见: Create a watermark (pdf Optional Content) that shows only when printing using PDFBox
现在我需要完全相反的方法:在屏幕上显示但不打印。我也尝试阅读 chapter 8.11 of PDF-1.7 spec,但未能按照我的要求创建 PDF(使用 Usage "View" 和 Event "View" 以及 "View" 和 [= 的组合) 38=]...)
PS:或者,满足要求的简单 PDF(在屏幕上显示 2 个单词,打印时只打印其中一个)肯定会有所帮助(可能 足够了),因为我认为我应该能够使用 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();