Created
August 5, 2015 20:57
-
-
Save JoelGeraci-Datalogics/586a5252f996cdac19a9 to your computer and use it in GitHub Desktop.
This sample shows how to add content and annotations to a layer on a PDF page. It also shows how to attach JavaScript to the PDF file at the document level.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright Datalogics, Inc. 2015 | |
*/ | |
package pdfjt.cookbook.document; | |
import com.adobe.internal.io.ByteReader; | |
import com.adobe.internal.io.ByteWriter; | |
import com.adobe.internal.io.InputStreamByteReader; | |
import com.adobe.pdfjt.core.types.ASString; | |
import com.adobe.pdfjt.pdf.document.PDFDocument; | |
import com.adobe.pdfjt.pdf.document.PDFNameDictionary; | |
import com.adobe.pdfjt.pdf.document.PDFOpenOptions; | |
import com.adobe.pdfjt.pdf.document.PDFSaveFullOptions; | |
import com.adobe.pdfjt.pdf.document.PDFText; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCConfig; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCGroup; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCGroupArray; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCObject; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCOrderList; | |
import com.adobe.pdfjt.pdf.graphics.optionalcontent.PDFOCProperties; | |
import com.adobe.pdfjt.pdf.graphics.xobject.PDFXObjectForm; | |
import com.adobe.pdfjt.pdf.interactive.action.PDFActionJavaScript; | |
import com.adobe.pdfjt.pdf.interactive.action.PDFActionURI; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFAnnotationLink; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFBorder; | |
import com.adobe.pdfjt.pdf.interactive.forms.PDFNamedJavaScripts; | |
import com.adobe.pdfjt.pdf.page.PDFPage; | |
import com.adobe.pdfjt.pdf.page.PDFPageMode; | |
import com.adobe.pdfjt.services.imageconversion.ImageManager; | |
import com.adobe.pdfjt.services.xobjhandler.XObjectApplyOptions; | |
import com.adobe.pdfjt.services.xobjhandler.XObjectUseOptions; | |
import java.awt.image.BufferedImage; | |
import java.io.InputStream; | |
import java.net.URL; | |
import java.util.Iterator; | |
import javax.imageio.ImageIO; | |
import javax.imageio.ImageReader; | |
import pdfjt.util.SampleFileServices; | |
/** | |
* This sample shows how to add content and annotations to a layer on a PDF | |
* page. It also shows how to attach JavaScript to the PDF file at the document | |
* level. | |
*/ | |
public class AddAnnotationsToLayers { | |
private static final String inputPDF = "http://dev.datalogics.com/cookbook/document/BlankInput.pdf"; | |
private static final String getReader = "http://dev.datalogics.com/cookbook/images/Get_Adobe_Acrobat_Reader_DC_web_button_158x39.fw.png"; | |
private static final String outputDir = "cookbook/Document/output/"; | |
static public void main(String[] args) throws Exception { | |
try { | |
/* | |
* First read in the two input files. The first one is the document | |
* that we are going to add the link to. The second is an image file | |
* we are going to use as the link graphic. | |
*/ | |
InputStream fis = new URL(inputPDF).openStream(); | |
ByteReader byteReader = new InputStreamByteReader(fis); | |
PDFDocument pdfDocument = PDFDocument.newInstance(byteReader, PDFOpenOptions.newInstance()); | |
// Read in the image file as a BufferedImage. | |
ImageReader reader = null; | |
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByFormatName("PNG"); | |
if (imageReaders.hasNext()) { | |
reader = imageReaders.next(); | |
} else { | |
System.out.println("A PNG Reader isn't available"); | |
System.exit(0); | |
} | |
reader.setInput(ImageIO.createImageInputStream(new URL(getReader).openStream())); | |
BufferedImage bufferedImage = reader.read(0); | |
/* | |
* Use the ImageManager class to convert the BufferedImage into a | |
* PDF XObject that can be added to the page and associated with a | |
* layer. | |
*/ | |
PDFXObjectForm linkImage = ImageManager.getXObjPDFImage(pdfDocument, bufferedImage, new XObjectUseOptions()); | |
/* | |
* Optional Content Groups (OCGs) are referred to as "Layers" in the | |
* Adobe Reader and Acrobat UI. We begin setting up the layer by | |
* creating a new named Optional Content Group and adding it to the | |
* Optional Content Properties object. | |
*/ | |
PDFOCGroup pdfOCGetReader = PDFOCGroup.newInstance(pdfDocument, "Get Reader"); | |
PDFOCProperties pdfOCProperties = PDFOCProperties.newInstance(pdfDocument); | |
pdfOCProperties.addOCG(pdfOCGetReader); | |
/* | |
* Then we need to set the default state of the Optional Content | |
* Group that we just created. To set the default state to be | |
* visible, we need to add it to the "OnList" in the default | |
* configuration dictionary. There is also an "OFFList" which we | |
* don't use in this sample. | |
*/ | |
PDFOCConfig pdfOCConfig = PDFOCConfig.newInstance(pdfDocument); | |
PDFOCGroupArray pdfOCGroupArrayOn = PDFOCGroupArray.newInstance(pdfDocument); | |
pdfOCGroupArrayOn.add(pdfOCGetReader); | |
pdfOCConfig.setONList(pdfOCGroupArrayOn); | |
/* | |
* We also need to set the order that the layers will appear when | |
* visible. This controls the rendering order. | |
*/ | |
PDFOCOrderList pdfOCOrderList = PDFOCOrderList.newInstance(pdfDocument); | |
pdfOCOrderList.addOCG(pdfOCGetReader); | |
pdfOCConfig.setOrderList(pdfOCOrderList); | |
pdfOCProperties.setDefaultOCConfigDict(pdfOCConfig); | |
/* | |
* Finally, we add all that to the PDF Catalog. We now have a layer | |
* that is configured to display properly in the Adobe Reader or | |
* Acrobat UI... | |
*/ | |
pdfDocument.requireCatalog().setOCProperties(pdfOCProperties); | |
/* | |
* ... which means we can now safely associate the linkImage XObject | |
* with the layer. | |
*/ | |
PDFOCObject.setOC(linkImage, pdfOCGetReader); | |
/* | |
* Then we add the image to the page about an inch from the upper | |
* left corner of the page and below the header. | |
*/ | |
XObjectApplyOptions applyOptions = new XObjectApplyOptions(); | |
PDFPage pageOne = pdfDocument.requirePages().getPage(0); | |
double llx = 72; | |
double lly = pageOne.getCropBox().height() - linkImage.getBBox().height() - 72 - 36; | |
applyOptions.setPosition(llx, lly); | |
applyOptions.applyXObjectForm(pageOne, linkImage, new XObjectUseOptions()); | |
/* | |
* Now we add a link annotation that sits on top of the image | |
* exactly. | |
*/ | |
PDFAnnotationLink pdfAnnotationLink = PDFAnnotationLink.newInstance(pdfDocument); | |
// Set the visual properties | |
PDFBorder pdfBorder = PDFBorder.newInstance(pdfDocument); | |
pdfBorder.setWidth(0); | |
pdfAnnotationLink.setBorder(pdfBorder); | |
// Set the link action | |
PDFActionURI pdfActionURI = PDFActionURI.newInstance(pdfDocument); | |
pdfActionURI.setURI(new ASString("http://www.adobe.com/go/reader")); | |
pdfAnnotationLink.setAction(pdfActionURI); | |
// Associate the link with the layer | |
PDFOCObject.setOC(pdfAnnotationLink, pdfOCGetReader); | |
// Position the link | |
double urx = 72 + linkImage.getBBox().width(); | |
double ury = pageOne.getCropBox().height() - 72 - 36; | |
pdfAnnotationLink.setRect(llx, lly, urx, ury); | |
// Finally, add the link to the page | |
pageOne.addAnnotation(pdfAnnotationLink); | |
/* | |
* Now set the document up to show the Layers panel when opened in | |
* Adobe Reader or Acrobat. | |
*/ | |
pdfDocument.requireCatalog().setPageMode(PDFPageMode.WithLayers); | |
/* | |
* At this point we've accomplished the goal of this sample. You now | |
* have two objects in the PDF file associated with a new layer; the | |
* image XObject and a link annotation. They can now be toggled on | |
* and off through the Adobe Reader and Acrobat UI. | |
* | |
* In this section we're going to add some JavaScript to the | |
* document that will run when it is first opened if the viewer is | |
* capable of running JavaScript. If the JavaScript detects a plugin | |
* that is unique to Adobe viewers, the layer state is set to false | |
* (hidden). If the JavaScript doesn't find the plugin or can't run, | |
* the layer remains visible. | |
* | |
* The script will hide both the graphic and the link by hiding the | |
* layer if the user is viewing the file in an Adobe tool but both | |
* will remain visible if not, prompting them to download it by | |
* clicking on the link. | |
* | |
* We begin by creating a JavaScript Action from a string of | |
* JavaScript code. | |
*/ | |
String javascriptCode = | |
"function getLayerByName(name) \n" | |
+ "{ \n" | |
+ " var ocgArray = this.getOCGs(); \n" | |
+ " layer = null; \n" | |
+ " for (var i=0; i < ocgArray.length; i++) { \n" | |
+ " if (ocgArray[i].name == name) { \n" | |
+ " layer = ocgArray[i];\n" | |
+ " break;\n" | |
+ " } \n" | |
+ " } \n" | |
+ " return layer; \n" | |
+ "}\n" | |
+ "plugIns = app.plugIns;\n" | |
+ "for (var i=0; i < plugIns.length; i++) {\n" | |
+ " if (plugIns[i].name == 'ADBE_Search') {\n" | |
+ " getLayerByName('Get Reader').state = false;\n" | |
+ " break;\n" | |
+ " }\n" | |
+ "}"; | |
PDFActionJavaScript adobeViewerTest = PDFActionJavaScript.newInstance(pdfDocument, | |
PDFText.newInstance(pdfDocument, javascriptCode)); | |
/* | |
* Get the Names dictionary from the PDF file if it exists or create | |
* a new one if it doesn't. This is where the document level | |
* JavaScripts are stored. Using "procureNameDictionary()" and | |
* procureNamedJavaScripts() then appending to them rather than | |
* creating new Objects and using "set" prevents what may be in the | |
* file already from being overwritten. | |
*/ | |
PDFNameDictionary pdfNameDictionary = pdfDocument.requireCatalog().procureNameDictionary(); | |
PDFNamedJavaScripts pdfNamedJavaScripts = pdfNameDictionary.procureNamedJavaScripts(); | |
pdfNamedJavaScripts.addEntry(new ASString("!Datalogics::AdobeViewerTest"), adobeViewerTest); | |
pdfNameDictionary.setNamedJavaScripts(pdfNamedJavaScripts); | |
// Save the file. | |
SampleFileServices.createDir(outputDir); | |
ByteWriter outputFile = SampleFileServices.getRAFByteWriter(outputDir + "LayeredDocument.pdf"); | |
pdfDocument.save(outputFile, PDFSaveFullOptions.newInstance()); | |
} finally { | |
// | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment