pCOS Cookbook

cookbook

interactive/link_destinations

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 destination and
Link annotations containing a "GoTo", "GoToE", "GoToR" or "URI" action.

Download Java Code     Show Output     Show Input PDF

package com.pdflib.cookbook.pcos.interactive;

import java.math.BigDecimal;

import com.pdflib.IpCOS;
import com.pdflib.cookbook.pcos.pcos_cookbook_example;

/**
 * Enumerate all links in the document and determine the destination.
 * <p>
 * The program is capable of printing out information about the following kinds
 * of objects:
 * 
 * - Link annotations containing a destination
 * - Link annotations containing a "GoTo", "GoToE", "GoToR" or "URI" action
 * 
 * Required software: pCOS interface 3 (pCOS 3.x, PDFlib+PDI/PPS 7.x, TET 2.2,
 * PLOP 3.x) <br>
 * Required data: PDF document
 * 
 * @version $Id: link_destinations.java,v 1.8 2015/11/16 11:53:16 stm Exp $
 */
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.
     * <p>
     * This method implements the different options for the destination syntax
     * that are described in chapter "8.2.1 Destinations" 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
     * @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("<no parameters>");
            }
            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("<no parameters>");
            }
            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.
     * <p>
     * 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.
     * <p>
     * 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,
                BigDecimal.ROUND_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).
     * <p>
     * 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, String full_rcs_file_name, String revision) {
        super(argv, readable_name, search_path, full_rcs_file_name, revision);
    }

    public static void main(String argv[]) {
        link_destinations example = new link_destinations(argv,
            "Link destinations", SEARCH_PATH,
            "$RCSfile: link_destinations.java,v $", "$Revision: 1.8 $");
        example.execute();
    }
}