PDFlib Cookbook

cookbook

fonts/glyph_availability

Check the availability of glyphs in a font.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * Glyph availability: Check the availability of glyphs in a font
 *
 * Load a font with "encoding=unicode". Then, for a specific Unicode character, 
 * output a row in a table containing the following information:
 *
 * 1) Font name
 * 2) Unicode code point and character name
 * 3) Glyph if available in the font
 * 4) Glyph name if available in the font
 * 
 * Required software: PDFlib/PDFlib+PDI/PPS 9
 * Required data: Font files
 */

package com.pdflib.cookbook.pdflib.fonts;


import com.pdflib.pdflib;
import com.pdflib.PDFlibException;

class glyph_availability {

    static private class testcase {
        testcase(String font_name, String font_optlist,
            String character, String character_desc) {
            this.font_name = font_name;
            this.font_optlist = font_optlist;
            this.character = character;
            this.character_desc = character_desc;
        }

        String font_name;
        String font_optlist;
        String character;
        String character_desc;
    }

    public static void main(String argv[]) {
        /* This is where the data files are. Adjust as necessary. */
        final String searchpath = "../input";

        String outfile = "glyph_availability.pdf";
        String title = "Glyph Availability";

        String optlist;
        pdflib p = null;
        int i, table;
        final double llx = 50, lly = 50, urx = 800, ury = 550;
        String result;
        int exitcode = 0;

        final String headers[] = { "Font name", "Unicode character", 
                                "Glyph", "Glyph name" };

        final testcase testcases[] = {
            new testcase("NotoSerif-Regular", "", "a", "U+0061 LATIN LETTER A"),
            
            new testcase("NotoSerif-Regular", "", "\u20AC", "U+20AC EURO SIGN"),            
                        
            new testcase("NotoSerif-Regular", "",  "\u017A", "U+017A LATIN SMALL LETTER Z WITH ACUTE"),

            new testcase("NotoSerif-Regular", "", "\u2D33", "U+2D33 TIFINAGH LETTER YAG"),

            new testcase("NotoNaskhArabic-Regular", "fallbackfonts={ {fontname=NotoSerif-Regular encoding=unicode} }",
                "\u0646", "U+0646 ARABIC LETTER NOON"),
            
            new testcase("NotoNaskhArabic-Regular", "fallbackfonts={ {fontname=NotoSerif-Regular encoding=unicode} }",
                "\u017A", "U+017A LATIN SMALL LETTER Z WITH ACUTE"),
            
            /*
             * Demonstration of Unicode characters beyond U+FFFF. The Unicode
             * character U+2000B (surrogate representation \uD840\DC0B) is
             * checked using a CJK font. The surrogates are resolved
             * by the Java compiler.
             * Languages which don't support surrogates or backslash syntax for
             * characters outside the BMP must use PDFlib character references
             * instead, e.g. 𠀋
             */
            new testcase("NotoSerifCJKjp-Regular", "", "\uD840\uDC0B",
                "U+2000B CJK UNIFIED IDEOGRAPH"),
        };

        try {
            p = new pdflib();

            p.set_option("searchpath={" + searchpath + "}");

            /*
             * This means that formatting and other errors will raise an
             * exception. This simplifies our sample code, but is not
             * recommended for production code.
             */
            p.set_option("errorpolicy=exception");

            /* Set an output path according to the name of the topic */
            if (p.begin_document(outfile, "") == -1) {
                throw new Exception("Error: " + p.get_errmsg());
            }

            p.set_info("Creator", "PDFlib Cookbook");
            p.set_info("Title", title);

            table = -1;

            /* Table header */
            optlist = "fittextline={fontname=NotoSerif-Bold "
                + "encoding=unicode fontsize=12} margin=4";
            for (i = 0; i < headers.length; i++) {
                table = p.add_table_cell(table, i + 1, 1, headers[i], optlist);
            }

            /* Create a table with feature samples, one feature per table row */
            for (i = 0; i < testcases.length; i++) {
                final testcase testcase = testcases[i];
                final int row = i + 2;

                /*
                 * Try to load the fonts, output a row that shows the missing
                 * font if a font can't be loaded.
                 */
                final String error_optlist = "fittextline={fontname=NotoSerif-Regular " 
                    + "encoding=unicode fontsize=12 fillcolor=red} "
                    + "margin=4";

                final String font_optlist = testcase.font_optlist
                                + " errorpolicy=return";

                final int font = p.load_font(testcase.font_name, "unicode",
                    font_optlist);
                if (font != -1) {
                    table = put_row(p, table, row, font, testcase);
                }
                else {
                    table = p.add_table_cell(table, 1, row,
                        testcase.font_name + ": font not available",
                        error_optlist);
                }
            }

            /*
             * Loop until all of the table is placed; create new pages as long
             * as more table instances need to be placed.
             */
            do {
                p.begin_page_ext(0, 0, "width=a4.height height=a4.width");

                optlist = "header=1 fill={{area=rowodd fillcolor={gray 0.9}}} "
                    + "stroke={{line=other}} ";

                /* Place the table instance */
                result = p.fit_table(table, llx, lly, urx, ury, optlist);

                if (result.equals("_error"))
                    throw new Exception("Couldn't place table: "
                        + p.get_errmsg());

                p.end_page_ext("");
            }
            while (result.equals("_boxfull"));

            p.end_document("");
        }
        catch (PDFlibException e) {
            System.err.println("PDFlib exception occurred:");
            System.err.println("[" + e.get_errnum() + "] " + e.get_apiname()
                + ": " + e.get_errmsg());
            exitcode = 1;
        }
        catch (Exception e) {
            System.err.println(e);
            exitcode = 1;
        }
        finally {
            if (p != null) {
                p.delete();
            }
            System.exit(exitcode);
        }
    }

    /**
     * Output one row with information regarding one specific character
     * 
     * @param p
     *            the pdflib object
     * @param table
     *            the table handle
     * @param row
     *            the number of the current row
     * @param font
     *            the font handle for the original font
     * @param t
     *            the current test case
     *            
     * @return the table handle
     * 
     * @throws PDFlibException
     * @throws Exception
     */
    static int put_row(pdflib p, int table, int row, int font, testcase t)
        throws PDFlibException, Exception {
        int col = 1;

        /*
         * Common option list for all columns except the "Actual glyph" column
         */
        final String common_optlist = "fittextline={fontname=NotoSerif-Regular " 
            + "encoding=unicode fontsize=12} margin=4";

        /*
         * Column 1: Font name
         */
        table = p.add_table_cell(table, col++, row, t.font_name, common_optlist);

        /*
         * Column 2: Unicode character
         */
        table = p.add_table_cell(table, col++, row, t.character_desc, common_optlist);

        /* The data type "Unichar" in option lists expects character references
         * without the &...; decoration, while the decoration is required in
         * text output functions.
         * We don't use charrefs in the examples, but if you need them and
         * want to pass them e.g. to info_font() you can resolve charrefs
         * as follows:
         * 
         * String t_plain = p.convert_to_unicode("utf16",
         *      t.character.getBytes("UTF-16"),
         *      "outputformat=utf16 charref=true");
         * 
         * Conversion from UTF-16 to UTF-16 may look a bit silly, but we use
         * the convert_to_unicode() method to resolve character references.
         * The result can be used in both option lists and text output functions.
         * This is only required if character references are used in the text.
         */

        /*
         * Determine whether a glyph is available, and if so, determine
         * the glyph name, if available.
         */
        final int gid = (int) p.info_font(font, "glyphid", "unicode=" + t.character);
        String display_character;
        String gn;
        if (gid != -1) {
            display_character = t.character;

            final int gn_idx = (int) p.info_font(font, "glyphname",
                                                    "unicode=" + t.character);

            if (gn_idx != -1) {
                gn = p.get_string(gn_idx, "");               
            }
            else {
                gn = "n/a";
            }
        }
        else {
            display_character = "n/a";
            gn = "n/a";
        }

        /*
         * Column 3: Actual glyph, if available.
         */
        final String testfont_optlist = "fittextline={font=" + font
                + " fontsize=12} margin=4";
        table = p.add_table_cell(table, col++, row, display_character,
                testfont_optlist);

        /*
         * Column 4: Glyph name
         */
        table = p.add_table_cell(table, col++, row, gn, common_optlist);

        return table;
    }
}