/*
* Enumerate all links in the document and determine the destination.
*
* The program is capable of printing out information about the following kinds
* of objects:
*
* - Link annotations containing a named destination
* - Link annotations containing a "GoTo", "GoToE", "GoToR" or "URI" action
*
* Required software: pCOS interface 8 (PDFlib+PDI/PPS 9, TET 4.1, PLOP 5.0)
* Required data: PDF document
*/
package com.pdflib.cookbook.pcos.interactive;
import java.math.BigDecimal;
import java.math.RoundingMode;
import com.pdflib.IpCOS;
import com.pdflib.cookbook.pcos.pcos_cookbook_example;
public class link_destinations extends pcos_cookbook_example {
/* This is where the data files are. Adjust as necessary. */
private final static String SEARCH_PATH = "../input";
public void example_code(IpCOS p, int doc) throws
Exception {
System.out.println("File name: " + p.pcos_get_string(doc, "filename"));
int pagecount = (int) p.pcos_get_number(doc, "length:pages");
for (int page = 0; page < pagecount; page++) {
final String annots_path = "pages[" + page + "]/annots";
String objtype = p.pcos_get_string(doc, "type:" + annots_path);
if (objtype.equals("null"))
continue;
int anncount = (int) p
.pcos_get_number(doc, "length:" + annots_path);
if (anncount == 0)
continue;
System.out.println("Link annotations on page " + (page + 1) + ":");
for (int ann = 0; ann < anncount; ann++) {
final String annot_path = annots_path + "[" + ann + "]";
String subtype = p
.pcos_get_string(doc, annot_path + "/Subtype");
if (!subtype.equals("Link"))
continue;
/*
* Check whether the annotation is a Link annotation with a
* destination.
*/
String dest_path = annot_path + "/Dest";
objtype = p.pcos_get_string(doc, "type:" + dest_path);
if (objtype.equals("string") || objtype.equals("name")
|| objtype.equals("array")) {
System.out.println("\tAnnotation #" + (ann + 1)
+ ": Link with destination");
print_link_info(p, doc, annot_path, dest_path);
continue;
}
/*
* Check whether the annotation is a Link annotation with an
* action.
*/
String action_path = annot_path + "/A";
objtype = p.pcos_get_string(doc, "type:" + action_path);
if (objtype.equals("dict")) {
System.out.println("\tAnnotation #" + (ann + 1)
+ ": Link with action");
print_link_action(p, doc, annot_path);
}
}
}
}
/**
* Print out information about a link.
*
* This method implements the different options for the destination syntax.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
* @param dest_path
* The pCOS path to the actual destination description
*
* @throws Exception
*/
private void print_link_info(IpCOS p, int doc, String annot_path,
String dest_path) throws Exception {
print_rect(p, doc, annot_path);
String contents_path = annot_path + "/Contents";
String objtype = p.pcos_get_string(doc, "type:" + contents_path);
if (objtype.equals("string")) {
System.out.println("\t\tDestination contents: \""
+ p.pcos_get_string(doc, contents_path) + "\"");
}
int dest_page_number = (int) p.pcos_get_number(doc, annot_path
+ "/destpage");
if (dest_page_number != -1) {
System.out.println("\t\tDestination page: " + dest_page_number);
}
objtype = p.pcos_get_string(doc, "type:" + dest_path);
if (objtype.equals("array")) {
String dest_kind = p.pcos_get_string(doc, dest_path + "[1]");
System.out.print("\t\t\"" + dest_kind + "\" destination: ");
if (dest_kind.equals("XYZ")) {
print_dest_value(p, doc, "left", dest_path + "[2]");
System.out.print(" ");
print_dest_value(p, doc, "top", dest_path + "[3]");
System.out.print(" ");
print_dest_value(p, doc, "zoom", dest_path + "[4]");
}
else if (dest_kind.equals("Fit")) {
System.out.print("");
}
else if (dest_kind.equals("FitH")) {
print_dest_value(p, doc, "top", dest_path + "[2]");
}
else if (dest_kind.equals("FitV")) {
print_dest_value(p, doc, "left", dest_path + "[2]");
}
else if (dest_kind.equals("FitR")) {
print_dest_value(p, doc, "left", dest_path + "[2]");
System.out.print(" ");
print_dest_value(p, doc, "bottom", dest_path + "[3]");
System.out.print(" ");
print_dest_value(p, doc, "right", dest_path + "[4]");
System.out.print(" ");
print_dest_value(p, doc, "top", dest_path + "[5]");
}
else if (dest_kind.equals("FitB")) {
System.out.print("");
}
else if (dest_kind.equals("FitBH")) {
print_dest_value(p, doc, "top", dest_path + "[2]");
}
else if (dest_kind.equals("FitBV")) {
print_dest_value(p, doc, "left", dest_path + "[2]");
}
else {
System.out.println("illegal destination type!");
}
System.out.println();
}
else if (objtype.equals("string")) {
String destination = p.pcos_get_string(doc, dest_path);
System.out.println("\t\tNamed destination (type string): "
+ destination);
}
else if (objtype.equals("name")) {
String destination = p.pcos_get_string(doc, dest_path);
System.out.println("\t\tNamed destination (type name): "
+ destination);
}
else {
System.out.println("\t\tIllegal destination type \"" + objtype);
}
}
/**
* Print a single value in a destination array.
* The member can either be a NULL object or a number.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param dest_member_name
* The name of the destination array element
* @param dest_value_path
* The pCOS path for the destination array element
*
* @throws Exception
*/
private void print_dest_value(IpCOS p, int doc, String dest_member_name,
String dest_value_path) throws Exception {
System.out.print(dest_member_name + " ");
String objtype = p.pcos_get_string(doc, "type:" + dest_value_path);
if (objtype.equals("null")) {
System.out.print("NULL");
}
else {
System.out.print(p.pcos_get_number(doc, dest_value_path));
}
}
/**
* Print out information about the action contained in a Link annotation
* dictionary.
* Prints out the "URI", "Goto", "GotoR" and "GotoE" actions stored under
* the "A" key in a link annotation dictionary (see chapter "8.5.3 Action
* Types" in the Adobe PDF Reference 1.7).
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_link_action(IpCOS p, int doc, String annot_path)
throws Exception {
String action_type = p.pcos_get_string(doc, annot_path + "/A/S");
System.out.println("\t\tAction type: \"" + action_type + "\"");
if (action_type.equals("URI")) {
print_uri(p, doc, annot_path);
}
else if (action_type.equals("GoTo")) {
print_goto(p, doc, annot_path);
}
else if (action_type.equals("GoToR")) {
print_goto_r(p, doc, annot_path);
}
else if (action_type.equals("GoToE")) {
print_goto_e(p, doc, annot_path);
}
else {
System.out.print("\t\tAction type \"" + action_type
+ "\" is not analyzed in this Cookbook example...");
}
System.out.println();
}
/**
* Prints out information about a Link annotation dictionary containing an
* "URI" action (see "TABLE 8.56 Additional entries specific to a URI
* action" in the Adobe PDF Reference 1.7).
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_uri(IpCOS p, int doc, String annot_path)
throws Exception {
print_rect(p, doc, annot_path);
String uri_path = annot_path + "/A/URI";
String uri = p.pcos_get_string(doc, uri_path);
System.out.println("\t\tURI: " + uri);
String ismap_path = annot_path + "/A/IsMap";
String objtype = p.pcos_get_string(doc, "type:" + ismap_path);
if (objtype.equals("boolean")) {
System.out.println("\t\tTrack mouse position: "
+ p.pcos_get_string(doc, ismap_path));
}
else {
System.out.println("\t\tTrack mouse position: <not specified>");
}
}
/**
* Print out the "Rect" dictionary member for an annotation dictionary. The
* numbers are rounded to two digits after the decimal point.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_rect(IpCOS p, int doc, String annot_path)
throws Exception {
System.out.print("\t\tAnnotation rectangle: ");
for (int i = 0; i < 4; i++) {
BigDecimal value = new BigDecimal(p.pcos_get_number(doc, annot_path
+ "/Rect[" + i + "]"));
BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP);
System.out.print(roundedValue.toString() + " ");
}
System.out.println();
}
/**
* Print out information about a Link annotation dictionary containing a
* "GoTo" action (see "TABLE 8.49 Additional entries specific to a go-to
* action" in the Adobe PDF Reference 1.7).
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_goto(IpCOS p, int doc, String annot_path)
throws Exception {
print_action_info(p, doc, annot_path);
}
/**
* Print out information about a link annotation with a "GoToE" action (see
* "TABLE 8.51 Additional entries specific to an embedded go-to action" in
* the Adobe PDF Reference 1.7).
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_goto_e(IpCOS p, int doc, String annot_path)
throws Exception {
print_goto_r_e_common(p, doc, annot_path);
print_target_dictionary(p, doc, annot_path + "/A/T", "");
}
/**
* Print out information about a Link annotation dictionary containing a
* "GoToR" action (see "TABLE 8.50 Additional entries specific to a remote
* go-to action" in the Adobe PDF Reference 1.7).
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_goto_r(IpCOS p, int doc, String annot_path)
throws Exception {
print_goto_r_e_common(p, doc, annot_path);
}
/**
* Print the common information for the "GoToR" and "GoToE" actions.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_goto_r_e_common(IpCOS p, int doc, String annot_path)
throws Exception {
print_action_info(p, doc, annot_path);
print_filespec(p, doc, annot_path);
System.out.print("\t\tOpen destination in new window: ");
String new_window_path = annot_path + "/A/NewWindow";
if (p.pcos_get_string(doc, "type:" + new_window_path).equals("boolean")) {
System.out.println(p.pcos_get_string(doc, new_window_path));
}
else {
System.out.println("<not specified>");
}
}
/**
* Print out information about a target dictionary (see "TABLE 8.52 Entries
* specific to a target dictionary" in the Adobe PDF Reference 1.7). Target
* dictionaries can contain target dictionaries, so this routine is
* recursive.
*
* @param p
* An IpCOS object
* @param doc
* A valid pCOS document handle
* @param annot_path
* The path to the link annotation dictionary
* @param tabs
* A string of \t characters to indent in recursive invocations
*
* @throws Exception
*/
private void print_target_dictionary(IpCOS p, int doc,
String target_dict_path, String tabs) throws Exception {
String objtype = p.pcos_get_string(doc, "type:" + target_dict_path);
if (objtype.equals("dict")) {
System.out.println(tabs + "\t\tTarget dictionary:");
String relationship_path = target_dict_path + "/R";
String relationship = p.pcos_get_string(doc, relationship_path);
if (relationship.equals("P")) {
System.out
.println(tabs
+ "\t\t\tRelationship: Target is parent of current document");
}
else if (relationship.equals("C")) {
System.out
.println(tabs
+ "\t\t\tRelationship: Target is child of current document");
String embedded_files_name_path = target_dict_path + "/N";
objtype = p.pcos_get_string(doc, "type:"
+ embedded_files_name_path);
if (objtype.equals("string")) {
System.out.println(tabs
+ "\t\t\tName of file in EmbeddedFiles name tree: "
+ p.pcos_get_string(doc, embedded_files_name_path));
}
String file_attachment_info_path = target_dict_path + "/P";
objtype = p.pcos_get_string(doc, "type:"
+ file_attachment_info_path);
if (objtype.equals("string")) {
System.out
.println(tabs
+ "\t\t\tNamed destination for page number of file attachment annotation: "
+ p.pcos_get_string(doc, file_attachment_info_path));
}
else if (objtype.equals("number")) {
int page_number_of_file_attachment_annotation = (int) p
.pcos_get_number(doc, file_attachment_info_path);
System.out.println(tabs
+ "\t\t\tPage number of file attachment annotation: "
+ (page_number_of_file_attachment_annotation + 1));
}
String annot_identifier_path = target_dict_path + "/A";
objtype = p.pcos_get_string(doc, "type:"
+ annot_identifier_path);
if (objtype.equals("string")) {
System.out.println(tabs
+ "\t\t\tUnique annotation identifier: "
+ p.pcos_get_string(doc, annot_identifier_path));
}
else if (objtype.equals("number")) {
int annot_index = (int) p.pcos_get_number(doc,
annot_identifier_path);
System.out.println(tabs
+ "\t\t\tIndex in \"Annots\" array: " + annot_index);
}
/*
* Recursive invocation to resolve embedded target dictionaries.
* The routine will simple return if there is no target
* dictionary present.
*/
print_target_dictionary(p, doc, target_dict_path + "/T", tabs
+ "\t");
}
else {
System.out.println("\t\t\tRelationship: Illegal value "
+ relationship);
}
}
}
/**
* Print out a file specification dictionary (see chapter "3.10.2 File
* Specification Dictionaries" in the Adobe PDF Reference 1.7).
*
* This implementation only looks at the "F", "DOS", "Mac" and "Unix" keys
* of the dictionary.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_filespec(IpCOS p, int doc, String annot_path)
throws Exception {
String filespec_path = annot_path + "/A/F";
String objtype = p.pcos_get_string(doc, "type:" + filespec_path);
if (objtype.equals("dict")) {
System.out.println("\t\tFile specification:");
print_filespec_member(p, doc, filespec_path, "DOS");
print_filespec_member(p, doc, filespec_path, "Mac");
print_filespec_member(p, doc, filespec_path, "Unix");
print_filespec_member(p, doc, filespec_path, "F");
}
}
/**
* Prints out a member of a file specification dictionary.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param filespec_path
* The path to the file specification dictionary
* @param platform
* The member of the file specification dictionary to print
*
* @throws Exception
*/
private void print_filespec_member(IpCOS p, int doc, String filespec_path,
String platform) throws Exception {
String platform_path = filespec_path + "/" + platform;
String objtype = p.pcos_get_string(doc, "type:" + platform_path);
if (objtype.equals("string")) {
System.out.println("\t\t\t" + platform + ": "
+ p.pcos_get_string(doc, platform_path));
}
}
/**
* Print common information about a Link annotation dictionary containing an
* action.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param annot_path
* The pCOS path to the link annotation dictionary
*
* @throws Exception
*/
private void print_action_info(IpCOS p, int doc, String annot_path)
throws Exception {
print_link_info(p, doc, annot_path, annot_path + "/A/D");
}
public link_destinations(String[] argv, String readable_name,
String search_path) {
super(argv, readable_name, search_path);
}
public static void main(String argv[]) {
link_destinations example = new link_destinations(argv,
"Link destinations", SEARCH_PATH);
example.execute();
}
}