/* Simple PDF glyph dumper based on PDFlib TET */

import java.io.*;
import java.util.*;
import com.pdflib.TETException;
import com.pdflib.TET;

public class glyphinfo
{
    /**
     * Global option list
     */
    static final String globaloptlist = "searchpath={{../data} " +
                        "{../../../resource/cmap}}";
    
    /**
     * Document-specific option list
     */
    static final String docoptlist = "";
    
    /**
     * Page-specific option list
     */
    static final String pageoptlist = "granularity=word";

    private static void print_color_value(Formatter formatter, TET tet, int doc, int colorid) throws com.pdflib.TETException
    {
        String csname;			/* color space name */
        int i;

        /* We handle only the fill color, but ignore the stroke color.
         * The stroke color can be retrieved analogously with the
         * keyword "stroke".
         */
        tet.get_color_info(doc, colorid, "usage=fill");

        if (tet.colorspaceid == -1 && tet.patternid == -1)
        {
            formatter.format(" (not filled)");
            return;
        }

        formatter.format(" (");

        if (tet.patternid != -1)
        {
            int patterntype =
                (int)tet.pcos_get_number(doc, "patterns[" + tet.patternid + "]/PatternType");

            if (patterntype == 1)	/* Tiling pattern */
            {
                int painttype =
                    (int) tet.pcos_get_number(doc, "patterns[" + tet.patternid + "]/PaintType");
                if (painttype == 1)
                {
                    formatter.format( "colored Pattern)");
                    return;
                }
                else if (painttype == 2)
                {
                    formatter.format( "uncolored Pattern, base color: ");
                    /* FALLTHROUGH to colorspaceid output */
                }
            }
            else if (patterntype == 2)	/* Shading pattern */
            {
                int shadingtype =
                    (int) tet.pcos_get_number(doc,
                            "patterns[" + tet.patternid + "]/Shading/ShadingType");

                formatter.format("shading Pattern, ShadingType=%d)", shadingtype);
                return;
            }
        }

        csname = tet.pcos_get_string(doc, "colorspaces[" + tet.colorspaceid + "]/name");

        formatter.format("%s", csname);

        /* Emit more details depending on the colorspace type */
        if (csname.equals( "ICCBased"))
        {
            int iccprofileid;
            String profilename;
            String profilecs;
            String errormessage;

            iccprofileid = (int) tet.pcos_get_number(doc,
                                    "colorspaces[" + tet.colorspaceid + "]/iccprofileid");

            errormessage = tet.pcos_get_string(doc,
                            "iccprofiles[" + iccprofileid + "]/errormessage");

            /* Check whether the embedded profile is damaged */
            if (errormessage.equals(""))
            {
                formatter.format(" (%s)", errormessage);
            }
            else
            {
                profilename =
                    tet.pcos_get_string(doc,
                        "iccprofiles[" + iccprofileid + "]/profilename");
                formatter.format( " '%s'", profilename);

                profilecs = tet.pcos_get_string(doc,
                        "iccprofiles[" + iccprofileid + "]/profilecs");
                formatter.format(" '%s'", profilecs);
            }
        }
        else if (csname.equals("Separation"))
        {
            String colorantname =
                tet.pcos_get_string(doc, "colorspaces[" + tet.colorspaceid + "]/colorantname");
            formatter.format(" '%s'", colorantname);
        }
        else if (csname.equals("DeviceN"))
        {
            formatter.format( " ");

            for (i=0; i < tet.components.length; i++)
            {
                String colorantname =
                    tet.pcos_get_string(doc,
                        "colorspaces[" + tet.colorspaceid + "]/colorantnames[" + i + "]");

                formatter.format( "%s", colorantname);

                if (i != tet.components.length-1)
                    formatter.format("/");
            }
        }
        else if (csname.equals( "Indexed"))
        {
            int baseid =
                (int) tet.pcos_get_number(doc, "colorspaces[" + tet.colorspaceid + "]/baseid" );

            csname = tet.pcos_get_string(doc, "colorspaces[" + baseid + "]/name");

            formatter.format( " %s", csname);

        }

        formatter.format( " ");
        for (i=0; i < tet.components.length; i++)
        {
            formatter.format( "%g", tet.components[i]);

            if (i != tet.components.length-1)
                formatter.format( "/");
        }
        formatter.format( ")");
    }

    
    public static void main (String argv[])
    {
        TET tet = null;
        
        try
        {
            if (argv.length != 2)
            {
                throw new Exception("usage: glyphinfo <filename> <outfilename>");
            }
            
            tet = new TET();
            
            tet.set_option(globaloptlist);
            
            int doc = tet.open_document(argv[0], docoptlist);
            
            if (doc == -1)
            {
                throw new Exception("Error " + tet.get_errnum() + " in "
                        + tet.get_apiname() + "(): " + tet.get_errmsg());
            }

            /*
             * The name for the text output file is generated from the
             * name of the input file by appending ".info.txt".
             */
            FileOutputStream fos = new FileOutputStream(argv[1]);
            /* print UTF-8 BOM */
            byte[] bom = new byte[] { (byte)0xEF, (byte)0xBB, (byte)0xBF };
            fos.write(bom);

            Writer outfp = new BufferedWriter(
                                    new OutputStreamWriter(fos, "UTF-8"));

            Formatter formatter = new Formatter(outfp, Locale.US);
            
            /* get number of pages in the document */
            int n_pages = (int) tet.pcos_get_number(doc, "length:pages");

            /* loop over pages in the document */
            for (int pageno = 1; pageno <= n_pages; ++pageno)
            {
                String text;
                int page;
                int previouscolor = -1;
                
                page = tet.open_page(doc, pageno, pageoptlist);

                if (page == -1)
                {
                    print_tet_error(tet, pageno);
                    continue; /* try next page */
                }

                /* Administrative information */
                formatter.format("[ Document: '" + 
                    tet.pcos_get_string(doc, "filename") + "' ]\n");

                formatter.format("[ Document options: '%s' ]\n", docoptlist);

                formatter.format("[ Page options: '%s' ]\n", pageoptlist);

                formatter.format("[ ----- Page %d ----- ]\n", pageno);


                /* Retrieve all text fragments */
                while ((text = tet.get_text(page)) != null)
                {
                    /* print the retrieved text */
                    outfp.write("[" + text + "]\n");

                    /* Loop over all glyphs and print their details */
                    while (tet.get_char_info(page) != -1)
                    {
                        final String fontname;

                        /* Fetch the font name with pCOS (based on its ID) */
                        fontname = tet.pcos_get_string(doc,
                                    "fonts[" + tet.fontid + "]/name");

                        /* Print the Unicode value ... */
                        formatter.format("U+%04X", tet.uv);

                        /* ...and the character itself if it is ASCII */
                        if (tet.uv >=0x20 && tet.uv <=0x7F)
                            formatter.format(" '%c'", tet.uv);
                        else 
                            formatter.format(" ???");

                        /* Print font name, size, and position */
                        formatter.format(" %s size=%.2f x=%.2f y=%.2f",
                            fontname, tet.fontsize, tet.x, tet.y);

                        /* Print the color id */
                        formatter.format(" colorid=%d", tet.colorid);

                        /* Check whether the text color changed */
                        if (tet.colorid != previouscolor){
                            print_color_value(formatter, tet, doc, tet.colorid);
                            previouscolor = tet.colorid;
                        }

                        /* Examine the "type" member */
                        if (tet.type == TET.CT_SEQ_START)
                            formatter.format(" ligature_start");

                        else if (tet.type == TET.CT_SEQ_CONT)
                            formatter.format(" ligature_cont");

                        /* Separators are only inserted for granularity > word*/
                        else if (tet.type == TET.CT_INSERTED)
                            formatter.format(" inserted");

                        /* Examine the bit flags in the "attributes" member */
                        if (tet.attributes != TET.ATTR_NONE) {
                            if ((tet.attributes & TET.ATTR_SUB) != 0)
                                    formatter.format("/sub");
                            if ((tet.attributes & TET.ATTR_SUP) != 0)
                                    formatter.format("/sup");
                            if ((tet.attributes & TET.ATTR_DROPCAP) != 0)
                                    formatter.format("/dropcap");
                            if ((tet.attributes & TET.ATTR_SHADOW) != 0)
                                    formatter.format("/shadow");
                            if ((tet.attributes & TET.ATTR_DEHYPHENATION_PRE) != 0)
                                    formatter.format("/dehyphenation_pre");
                            if ((tet.attributes & TET.ATTR_DEHYPHENATION_ARTIFACT) != 0)
                                    formatter.format("/dehyphenation_artifact");
                            if ((tet.attributes & TET.ATTR_DEHYPHENATION_POST) != 0)
                                    formatter.format("/dehyphenation_post");
                            if ((tet.attributes & TET.ATTR_ARTIFACT) != 0)
                                    formatter.format("/Artifact");
                        }

                        formatter.format("\n");
                    }

                    formatter.format("\n");
                }
                if (tet.get_errnum() != 0)
                {
                    print_tet_error(tet, pageno);
                }

                tet.close_page(page);
            }

            tet.close_document(doc);
            outfp.close();
        }
        catch (TETException e)
        {
            System.err.println("TET exception occurred in glyphinfo sample:");
            System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() +
                            ": " + e.get_errmsg());
        }
        catch (Exception e)
        {
            System.err.println(e);
        }
        finally
        {
            if (tet != null) {
                tet.delete();
            }
        }
    }

    /**
     * Report a TET error.
     * 
     * @param tet The TET object
     * @param pageno The page number on which the error occurred
     */
    private static void print_tet_error(TET tet, int pageno)
    {
        System.err.println("Error " + tet.get_errnum() + " in  "
                + tet.get_apiname() + "() on page " + pageno + ": "
                + tet.get_errmsg());
    }
}
