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