BASKET
Search
PDFlib

fonts/glyph_availability

Download Java Code     Switch to PHP Code     Show Output PDF

/* $Id: glyph_availability.java,v 1.14 2017/01/26 13:13:35 stm Exp $

 *

 * 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 codepoint and character name

 * 3) Glyph if available

 * 4) Glyph name if available

 *

 * Required software: PDFlib/PDFlib+PDI/PPS 9

 * Required data: Font files. The sample looks for the font file "arialuni.ttf"

 * ("Arial Unicode MS"). Put this file into the "extra_input" directory.

 *

 * This example is not run by default from the Ant build.xml file and can be

 * executed either specifically by invoking "ant glyph_availability" or together

 * with the other topics that require extra configuration by invoking "ant

 * run-extra-topics".

 */


package com.pdflib.cookbook.pdflib.fonts;


import java.util.regex.Matcher;

import java.util.regex.Pattern;


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, boolean charref) {

            this.font_name = font_name;

            this.font_optlist = font_optlist;

            this.character = character;

            this.character_desc = character_desc;

            this.charref = charref;

        }


        String font_name;

        String font_optlist;

        String character;

        String character_desc;

        boolean charref;

    }


    public static void main(String argv[]) {

        /* This is where the data files are. Adjust as necessary. */

        final String searchpath = "../input";

        /* Put extra fonts into the "extra_input" directory */

        final String extra_searchpath = "../extra_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("Helvetica", "", "a", "LATIN LETTER A", false),

            new testcase("ScheherazadeRegOT", "", "\u0646", "ARABIC LETTER NOON", false),

            new testcase("arialuni", "", "\u0646", "ARABIC LETTER NOON", false),

            /* same character as above, but as PDFlib character reference */

            new testcase("Helvetica", "", "ن", "ARABIC LETTER NOON", true),

            new testcase("Helvetica", "", "\u2D33", "TIFINAGH LETTER YAG", false),

            new testcase("GenI102", """\u017A", "LATIN SMALL LETTER Z WITH ACUTE", false),

            new testcase("Norasi", "", "\u017A", "LATIN SMALL LETTER Z WITH ACUTE", false),

            new testcase("Norasi", "", "\u20AC", "EURO SIGN", false),

           

            /*

             * Demonstration of Unicode character beyond U+FFFF. With a PDFlib

             * character reference this is straightforward. With Java characters

             * this must be expressed with a UTF-16 surrogate pair. The Unicode

             * PUA character U+F0001 is checked in both ways in the

             * "fallback.ttf" font.

             */

            new testcase("fallback", "", "󰀁",

                "PUA CHARACTER U+F0001 (character reference)", true),

            new testcase("fallback", "", "\uDB80\uDC01",

                "PUA CHARACTER U+F0001 (surrogate pair)", false),

        };


        try {

            p = new pdflib();


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

            p.set_option("searchpath={" + extra_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");

           

            /* The test cases can contain character references */

            p.set_option("charref=true");


            /* 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 + " $Revision: 1.14 $");


            table = -1;


            /* Table header */

            optlist = "fittextline={fontname=Helvetica-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=Helvetica "

                    + "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.print("PDFlib exception occurred:\n");

            System.err.print("[" + e.get_errnum() + "] " + e.get_apiname()

                + ": " + e.get_errmsg() + "\n");

            exitcode = 1;

        }

        catch (Exception e) {

            System.err.println(e.getMessage());

            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=Helvetica "

            + "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 value and name of Unicode character

         */

        final String uv = get_unichar(t.character, t.charref);

        final String char_desc = uv + " (" + t.character_desc + ")";

        table = p.add_table_cell(table, col++, row, char_desc, common_optlist);


        /*

         * 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=" + uv);


        String display_character;

        String gn;

        if (gid != -1) {

            display_character = t.character;


            final int gn_idx = (int) p.info_font(font, "glyphname",

                                                    "unicode=" + uv);

            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;

    }


    /**

     * Get a PDFlib "Unichar" string (see PDFlib Tutorial, "1.1.1 Syntax",

     * "Unichar").

     *

     * @param character

     *            A String containing logically a single character.

     * @param charref

     *            If true, the character parameter contains a PDFlib character

     *            reference, otherwise it contains the UTF-16 representation of

     *            a single Unicode code point (which can either be a single char

     *            or a surrogate pair for Unicode code points beyond U+FFFF).

     *

     * @return the character in PDFlib "Unichar" notation

     *

     * @throws Exception Incorrect test case supplied

     */

    static String get_unichar(String character, boolean charref)

            throws Exception {

        String result;

       

        if (charref)

        {

            /* Extract Unicode code point value from character reference */

            Pattern p = Pattern.compile("^&#x([A-Fa-f\\d]{4,5});$",

                                        Pattern.CASE_INSENSITIVE);

            Matcher m = p.matcher(character);

            if (!m.matches()) {

                throw new Exception("Incorrect character reference '"

                    + character + "' in test case with charref=true");

            }

           

            result = "U+" + m.group(1);

        }

        else

        {

            /* Determine the number of Unicode code points, which must be 1 */

            int codePointCount =

                Character.codePointCount(character, 0, character.length());

           

            if (codePointCount != 1) {

                throw new Exception("The number of Unicode code points in a " +

                                "test case without charref=true must be 1");

            }

           

            /*

             * Get the Unicode code point corresponding to the sequence of

             * Java chars in the string.

             */

            int codePoint = Character.codePointAt(character, 0);

           

            result = String.format("U+%04X", codePoint);

        }

       

        return result;

    }

}