/* Simple PDF glyph dumper based on PDFlib TET
 *
 * $Id: glyphinfo.java,v 1.6 2010/07/15 10:34:12 rjs Exp $
 */

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";
    
    public static void main (String argv[])
    {
        TET tet = null;
        
	try
        {

	    if (argv.length != 2)
            {
                throw new Exception("usage: glyphinfo <filename> <outfilename>");
            }

            /*
             * 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);

            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());
            }
            
            /* 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;
		
		page = tet.open_page(doc, pageno, pageoptlist);

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

		/* Administrative information */
		formatter.format("\n[ 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)
		{
		    int ci;

		    /* print the retrieved text */
		    outfp.write("[" + text + "]\n");

		    /* Loop over all glyphs and print their details */
		    while ((ci = 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 character */
			formatter.format("U+%04X", tet.uv);

			/* ...and its UTF8 representation */
			formatter.format(" '%c'", tet.uv);

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

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

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

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

			/* Examine the bit flags in the "attributes" member */
			final int ATTR_NONE = 0;
			final int ATTR_SUB = 1;
			final int ATTR_SUP = 2;
			final int ATTR_DROPCAP = 4;
			final int ATTR_SHADOW = 8;
			final int ATTR_DH_PRE = 16;
			final int ATTR_DH_ARTIFACT = 32;
			final int ATTR_DH_POST = 64;

			if (tet.attributes != ATTR_NONE)
			{
			    if ((tet.attributes & ATTR_SUB) == ATTR_SUB)
				formatter.format("/sub");
			    if ((tet.attributes & ATTR_SUP) == ATTR_SUP)
				formatter.format("/sup");
			    if ((tet.attributes & ATTR_DROPCAP) == ATTR_DROPCAP)
				formatter.format("/dropcap");
			    if ((tet.attributes & ATTR_SHADOW) == ATTR_SHADOW)
				formatter.format("/shadow");
			    if ((tet.attributes & ATTR_DH_PRE) == ATTR_DH_PRE)
				formatter.format("/dehyphenation_pre");
			    if ((tet.attributes & ATTR_DH_ARTIFACT) == ATTR_DH_ARTIFACT)
				formatter.format("/dehyphenation_artifact");
			    if ((tet.attributes & ATTR_DH_POST) == ATTR_DH_POST)
				formatter.format("/dehyphenation_post");
			}

			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.getMessage());
        }
        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());
    }
}
