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