text_output/emoji_sequences
Modify emoji with Unicode sequences.
Download Java Code Switch to PHP Code Show Output
/*
* Emoji sequences
*
* This topic demonstrates the following aspects:
* - how to deal with supplemental Unicode characters in your code
*
* - font-specific features for color fonts:
* - Emoji zerowidth joiner sequences for multi-person groupings, role,
* gender, hair components and other modifications using
* U+200D ZERO WIDTH JOINER (ZWJ)
*
* - Skintone modifiers for adjusting the skin color of emoji using
* U+1F3FB EMOJI MODIFIER FITZPATRICK TYPE 1-2
* ...
* U+1F3FF EMOJI MODIFIER FITZPATRICK TYPE 6
*
* - Emoji flag sequences for creating flags from regional indicator
* characters U+1F1E6 REGIONAL INDICATOR SYMBOL LETTER A etc.
*
* - Emoji keycap sequences using digits and
* U+FE0F EMOJI PRESENTATION SELECTOR (VS16)
* U+20E3 COMBINING ENCLOSING KEYCAP
*
* These sequences are defined in the Unicode standard, but their
* implementation must be provided by the OpenType feature definitions
* in the font. Comprehensive tables are available at
* https://unicode.org/Public/emoji/14.0/emoji-zwj-sequences.txt
* https://unicode.org/Public/emoji/14.0/emoji-sequences.txt
*
* Required software: PDFlib/PDFlib+PDI/PPS 10
* Required data: color emoji font
*
* We use the font EmojiOneColor which offers a variety of colorful glyphs
* as well as OpenType feature definitions for the modifications above.
* It is freely available at
* https://github.com/adobe-fonts/emojione-color
*
* Some Unicode sequences are not supported by this font. You can use the
* Windows font "Segoe UI Emoji" for additional examples (see below).
*/
/*
* Many Emoji characters are encoded with values > U+FFFF (supplemental
* characters) which requires special treatment depending on the
* programming language and development environment.
*
* A "String" object in Java represents strings in UTF-16 format.
* This means that Unicode values outside the BMP, i.e. > U+FFFF,
* must be represented as surrogate pairs. Unicode code points outside the
* BMP cannot be represented in a single "char" or "Character".
*
* You can initialize Strings in the following ways:
* - Supply the Unicode code point as "int" value and convert it to a String:
* String unistring = new String(Character.toChars(0x1F0CF));
*
* - Supply the surrogate pair (two UTF-16 code units):
* String unistring = new String("\uD83C\uDCCF");
*
* - Supply the Unicode character directly in the Java source and
* store it in a suitable Unicode encoding such as UTF-8 or UTF-16
* (not the commonly used cp1252):
* String unistring = new String("X");
* (Using "X" as placeholder here to keep this source in cp1252).
*
* The Java compiler must be informed about the source encoding,
* either directly with the javac option encoding="utf8" or
* by appropriate settings in the IDE.
*
* - PDFlib character references are independent of the development
* environment and can be enabled with the "charref" option, e.g.
* p.fit_textline("🃏",
* 100, 100, "charref=true fontname=EmojiOneColor fontsize=50");
*/
package com.pdflib.cookbook.pdflib.text_output;
import com.pdflib.pdflib;
import com.pdflib.PDFlibException;
class emoji_sequences {
public static void main(String argv[]) {
/* This is where the data files are. Adjust as necessary. */
final String searchpath = "../input";
final String outfile = "emoji_sequences.pdf";
String title = "Emoji sequences";
pdflib p = null;
int i, table;
final double llx = 25, lly = 25, urx = 820, ury = 550;
String result;
int exitcode = 0;
/* This font will be used unless another one is specified in the table */
final String defaulttestfont = "EmojiOneColor";
final String headers[] = {
"Description",
"Font name",
"Raw input",
"Isolated characters",
"Combined characters"
};
class testcase {
testcase(String description, String fontname, String text) {
this.description = description;
this.fontname = fontname;
this.text = text;
}
String description;
String fontname;
String text;
}
final testcase testcases[] = {
new testcase("ZWJ grouping", "",
"👨‍👩‍👧"),
new testcase("skin tone", "",
"👦🏻👦🏼👦🏽" +
"👦🏾👦🏿"),
new testcase("emoji flag", "",
"🇲🇹 🇦🇪 🇬🇧"),
new testcase("emoji keycap", "",
"0️⃣ 9️⃣ #️⃣"),
/* The following examples don't work with EmojiOneColor, but e.g.
* with the Windows font "Segoe UI Emoji".
new testcase("ZWJ gender", "Segoe UI Emoji",
"🏊‍♀️" +
"🏊‍♂️"),
new testcase("ZWJ gender", "Segoe UI Emoji",
"🧜‍♂ 🧜‍♀"),
new testcase("skin tone and gender", "Segoe UI Emoji",
"🧜🏿‍♂ 🧜🏿‍♀"),
new testcase("ZWJ hair components: red/bald/white", "Segoe UI Emoji",
"👨‍🦰" +
"👨‍🦲" +
"👨‍🦳"),
new testcase("ZWJ role: man farmer", "Segoe UI Emoji",
"👨‍🌾"),
new testcase("ZWJ role: woman farmer", "Segoe UI Emoji",
"👩‍🌾"),
*/
};
try {
String optlist;
p = new pdflib();
p.set_option("searchpath={" + searchpath + "}");
p.set_option("charref=true");
/*
* 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 */
for (i = 0; i < headers.length; i++) {
final int col = i + 1;
optlist =
"fittextline={fontname=NotoSerif-Bold fontsize=12} "
+ "margin=4";
table = p.add_table_cell(table, col, 1, headers[i], optlist);
}
/* Create a table with feature samples, one feature per table row */
for (i = 0; i < testcases.length; i += 1) {
final testcase testcase = testcases[i];
final int row = i + 2;
int tf;
/*
* Use the entry in the test table if available, and the default
* test font otherwise.
*/
final String testfont =
testcase.fontname.length() > 0
? testcase.fontname
: defaulttestfont;
int col = 1;
/* Common option list for columns 1-3 */
optlist =
"fittextline={fontname=NotoSerif-Regular fontsize=12} "
+ "margin=4 colwidth=10%";
/* Column 1: feature description */
table = p.add_table_cell(table, col++, row,
testcase.description, optlist);
/* Column 2: font name */
table = p.add_table_cell(table, col++, row, testfont, optlist);
/* Column 3: raw input */
tf = p.add_textflow(-1, testcase.text,
"charref=false fontname=NotoSerif-Regular " +
"fontsize=" +(testcase.text.length() < 35 ? 12 : 8) + " alignment=center");
table = p.add_table_cell(table, col++, row, "",
"colwidth=20% textflow=" + tf + " margin=4");
/* Column 4: raw input text with all features disabled */
optlist = "fittextline={features=_none colormode=combined fontname={" + testfont
+ "} fontsize=20} margin=4";
table = p.add_table_cell(table, col++, row, testcase.text,
optlist);
/* Column 5: text with enabled feature */
optlist = "fittextline={fontname={" + testfont + "} fontsize=20} margin=4";
table = p.add_table_cell(table, col++, row, testcase.text,
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");
/* Place the table */
optlist = "header=1 fill={{area=rowodd "
+ "fillcolor={gray 0.9}}} stroke={{line=other}} ";
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);
}
}
}