pCOS Cookbook

cookbook

special/output_intents updated

Analyze PDF/A, PDF/X and PDF 2.0 output intents on document or page level and print information about the corresponding ICC profiles.

Download Java Code  Show Output  Show Output  Show Input (pdfa.pdf) 

/*
 * Analyze PDF/A, PDF/X and PDF 2.0 output intents on document or page level
 * and print information about the corresponding ICC profiles.
 *
 * Required software: pCOS interface 10 (PDFlib+PDI 10, TET 5.x, PLOP 5.x)
 *
 * Required data: PDF document
 */
package com.pdflib.cookbook.pcos.special;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

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

public class output_intents 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 {

        String filename = p.pcos_get_string(doc, "filename");
        System.out.println("File name: " + filename);

        int output_intent_count = (int) p.pcos_get_number(doc,
            "length:/Root/OutputIntents");

        // Search document output intents
        if (output_intent_count == 0)
            System.out.println("No document output intent found");
        else
            for (int oi = 0; oi < output_intent_count; oi += 1)
            {
                System.out.println("Document output intent " + (oi + 1) + ":");
                process_output_intent(p, doc, filename, oi);
            }
        
        // Search page output intents (requires PDF 2.0)
        int page_count = (int) p.pcos_get_number(doc, "length:pages");
        for (int page = 0; page < page_count; page += 1)
        {
            output_intent_count = (int) p.pcos_get_number(doc,
                    "length:pages[" + page + "]/OutputIntents");

            for (int oi = 0; oi < output_intent_count; oi += 1)
            {
                System.out.println("Page " + (page + 1) + ", output intent " + (oi + 1) + ":");
                process_output_intent(p, doc, filename, oi);
            }
        }
    }

    /**
     * Examines the output intent given by parameter oi, and writes out ICC
     * profile if applicable.
     * 
     * @param p
     *            IpCOS object
     * @param doc
     *            document handle
     * @param filename
     *            name of the PDF input document
     * @param oi
     *            index in "/Root/OutputIntents" array
     * 
     * @throws Exception
     */
    private void process_output_intent(IpCOS p, int doc, String filename, int oi)
        throws  Exception {
        /*
         * The pCOS path to the given output intent
         */
        final String oi_key = "/Root/OutputIntents[" + oi + "]";
        int iccprofileid = -1;
        String objtype;

        print_info(p, doc, oi_key + "/S", "Subtype", "name", true);
        print_info(p, doc, oi_key + "/OutputConditionIdentifier", "Identifier", "string", true);

        // Check whether an ICC profile is directly included in the output intent 
        objtype = p.pcos_get_string(doc, "type:" + oi_key + "/DestOutputProfile");
        if (objtype.equals("stream"))
        {
        	iccprofileid = (int) p.pcos_get_number(doc, oi_key + "/DestOutputProfile/iccprofileid");
        	
            byte[] contents = p.pcos_get_stream(doc, "", oi_key + "/DestOutputProfile");
            if (contents != null && contents.length > 0)
            {
                String subtype = p.pcos_get_string(doc, oi_key + "/S");
                write_profile(filename, subtype, contents);
            }
            else {
                System.out.println("  No direct ICC profile found");
            }
        }
        else
        {
            // Check whether an ICC profile is available as embedded file
            objtype = p.pcos_get_string(doc, "type:" + oi_key + "/DestOutputProfileRef");
            
            if (objtype.equals("dict")) {
            	iccprofileid = (int) p.pcos_get_number(doc, oi_key + "/DestOutputProfileRef/iccprofileid");

                objtype = p.pcos_get_string(doc, "type:" + oi_key + "/DestOutputProfileRef/URLs[0]/EF/F");
                if (objtype.equals("stream"))
                {
                    byte[] contents = p.pcos_get_stream(doc, "", oi_key + "/DestOutputProfileRef/URLs[0]/EF/F");
                    if (contents != null && contents.length > 0)
                    {
                        String subtype = p.pcos_get_string(doc, oi_key + "/S");
                        System.out.println("  Referenced ICC profile with attached data found");
                        write_profile(filename, subtype, contents);
                    }
                }

                // Check whether a referenced ICC profile is present
                objtype = p.pcos_get_string(doc, "type:" + oi_key + "/DestOutputProfileRef/URLs[0]/F");
                if (objtype.equals("string")) {
                    System.out.println("  Externally referenced ICC profile found");
                }
                objtype = p.pcos_get_string(doc, "type:" + oi_key
                        + "/DestOutputProfileRef/ProfileName");
                if (objtype.equals("string")) {
                    System.out.println("  Referenced ICC profile name: '" + 
                        p.pcos_get_string(doc, oi_key + "/DestOutputProfileRef/ProfileName") + "'");
                }
            }
            else {
                System.out.println("  Neither direct nor referenced ICC profile found");
            }
        }
        
        if (iccprofileid != -1)
        {
            String errormessage = p.pcos_get_string(doc, "iccprofiles[" + iccprofileid + "]/errormessage");
                
            // Check whether the embedded profile is damaged
            if (errormessage != null && errormessage.length() > 0) {
                System.out.println("ICC profile damaged (" + errormessage + ")");
            }
            else {
		        // Print ICC profile details using pCOS pseudo objects
		        print_info(p, doc, "iccprofiles[" + iccprofileid + "]/deviceclass", "device class", "string", true);
		        print_info(p, doc, "iccprofiles[" + iccprofileid + "]/profilecs", "profile colorspace", "string", true);
		        print_info(p, doc, "iccprofiles[" + iccprofileid + "]/iccversion", "ICC version", "string", true);
		        print_info(p, doc, "iccprofiles[" + iccprofileid + "]/fromCIE", "BtoA1 tag present", "boolean", true);
		        print_info(p, doc, "iccprofiles[" + iccprofileid + "]/toCIE", "AtoB1 tag present", "boolean", true);
            }
        }
    }

    /**
     * Prints out one of the keys in the output intent dictionary.
     * 
     * @param p
     *            IpCOS object
     * @param doc
     *            document handle
     * @param key
     *            key of interest in the output intent dictionary
     * @param label
     *            human-readable lable
     * @param type
     *            expected type of the value in the dictionary
     * @param required
     *            if true the absence of the key causes an exception
     * 
     * @throws Exception
     *             a pCOS error occurred
     * @throws Exception
     *             a required key was not found, the PDF document is damaged
     */
    private void print_info(IpCOS p, int doc, String key, String label,
        String type, boolean required) throws  Exception {
        String objtype = p.pcos_get_string(doc, "type:" + key);

        System.out.print("  " + label + ": ");

        if (objtype.equals(type)) {
            System.out.print("'" + p.pcos_get_string(doc, key) + "'");
        }
        else {
            if (required) {
                throw new Exception("Required key '" + key
                    + "' is missing, cannot continue");
            }
            System.out.print("(not found)");
        }

        System.out.println();
    }

    /**
     * Writes the ICC profile to a file.
     * 
     * @param filename
     *            name of PDF input document
     * @param subtype
     *            output intent subtype from output intent dictionary
     * @param contents
     *            the contents of the distiller profile
     * 
     * @throws Exception
     *             unexpected suffix of input file name
     */
    private void write_profile(String filename, String subtype, byte[] contents)
        throws Exception {
        File original_path = new File(filename);
        String base_name = original_path.getName();

        /*
         * Strip off the ".pdf" part of the file name
         */
        String suffix = "";
        if (base_name.length() >= 4) {
            suffix = base_name.substring(base_name.length() - 4);
        }

        if (suffix.compareToIgnoreCase(".pdf") != 0) {
            throw new Exception("Input document has unexpected suffix \""
                + suffix + "\" (expected \".pdf\")");
        }

        base_name = base_name.substring(0, base_name.length() - 4);

        try {
            /*
             * create a new file in the current directory and write the
             * contents of the ICC profile to it
             */
            File icc_profile_file = new File(base_name + "_" + subtype + ".icc");

            FileOutputStream icc_profile_stream = new FileOutputStream(
                icc_profile_file);
            icc_profile_stream.write(contents);
            icc_profile_stream.close();

            System.out.println("  ICC profile extracted to file \""
                + icc_profile_file.getName() + "\"");
        }
        catch (IOException e) {
            System.err.println("IOException occured:");
            e.printStackTrace();
        }
    }

    public output_intents(String[] argv, String readable_name,
        String search_path) {
        super(argv, readable_name, search_path);
    }

    public static void main(String argv[]) {
        output_intents example = new output_intents(argv,
            "Output intent ICC profiles", SEARCH_PATH);
        example.execute();
    }
}