text_output/emoji_sequences
Modify emoji with Unicode sequences.
Download PHP Code Switch to Java Code Show Output
<?php
/*
* 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.
*
* You can initialize PHP strings with supplemental characters in the
* following ways:
*
* - Supply the Unicode code point in hexadecimal format (surrogate pairs are
* not supported):
* $unistring = "\u{1F0CF}";
*
* - Supply the Unicode character directly in the PHP source and store the
* source file in UTF-8 format.
*
* - 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");
*/
/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(__FILE__,3)."/input";
$outfile = "";
$title = "Emoji sequences";
$exitcode = 0;
$llx = 25; $lly = 25; $urx = 820; $ury = 550;
/* This font will be used unless another one is specified in the table */
$defaulttestfont = "EmojiOneColor";
$headers = array(
"Description",
"Font name",
"Raw input",
"Isolated characters",
"Combined characters"
);
class testcase {
public function __construct($description, $fontname, $text) {
$this->description = $description;
$this->fontname = $fontname;
$this->text = $text;
}
public $description;
public $fontname;
public $text;
}
$testcases = array(
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 ZWJ 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 {
$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, "") == 0) {
throw new Exception("Error: " . $p->get_errmsg());
}
$p->set_info("Creator", "PDFlib Cookbook");
$p->set_info("Title", $title);
$table = 0;
/* Table header */
for ($i = 0; $i < count($headers); $i++) {
$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 < count($testcases); $i += 1) {
$testcase = $testcases[$i];
$row = $i + 2;
/*
* Use the entry in the test table if available, and the default
* test font otherwise.
*/
$testfont =
strlen($testcase->fontname) > 0
? $testcase->fontname
: $defaulttestfont;
$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(0, $testcase->text,
"charref=false fontname=NotoSerif-Regular " .
"fontsize=" .(strlen($testcase->text) < 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 == "_error") {
throw new Exception("Couldn't place table: " . $p->get_errmsg());
}
$p->end_page_ext("");
}
while ($result == "_boxfull");
$p->end_document("");
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=emoji_sequences.pdf");
print $buf;
}
catch (PDFlibException $e) {
echo ("PDFlib exception occurred:\n" . "[" . $e->get_errnum() . "] " .
$e->get_apiname() . ": " . $e->get_errmsg() . "\n");
exit(1);
}
catch (Throwable $e) {
echo ("PHP exception occurred: " . $e->getMessage() . "\n");
exit(1);
}
$p = 0;
?>