*
* 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.
*/
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;
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.12 $");
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");
}
catch (Exception e) {
System.err.println(e.getMessage());
}
finally {
if (p != null) {
p.delete();
}
}
}
/**
* 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;
}
}