> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/ru/podrobnye-stati/10-an-overview-of-technologies-supporting-the-use-of-colour-emoji-fonts-in-latex.md).

# Обзор технологий, поддерживающих использование цветных шрифтов emoji в LaTeX

## Введение

В этой статье представлен обзор различных [справочных тем](#which-topics-do-we-cover) связанных с использованием цветных шрифтов OpenType для набора цветных эмодзи в LaTeX. Мы постарались представить широкий спектр материалов, рассчитанных на самый разный круг интересов и уровень подготовки. Чтобы статья оставалась обозримой, в нашем освещении некоторых тем опущено много технических подробностей, но мы надеемся, что материала достаточно, чтобы сориентировать вас в исследовании набора цветных эмодзи в LaTeX.

**Обновление (июль 2023)**: эта статья была впервые опубликована в августе 2021 года и переработана в июле 2023 года для обновления раздела о [Использование цветных шрифтов OpenType на основе SVG с LuaHBTeX](#using-svg-based-opentype-color-fonts-with-luahbtex).

### Какие темы мы рассматриваем?

В этой статье рассматриваются следующие общие темы:

* Юникод: стандарт, который кодирует эмодзи как символы и формализует их ожидаемое поведение в приложениях для обработки текста и набора.
* Цветные шрифты OpenType: специализированные шрифты, которые обеспечивают красочные изображения символов эмодзи, отображаемых в вашем документе LaTeX.
* Формирование текста: введение в ключевой компонент набора текстов на сложных письменностях и эмодзи.
* HarfBuzz: компонент LuaHBTeX, который обеспечивает продвинутый многоязычный набор и использование цветных шрифтов OpenType для набора эмодзи в LaTeX.
* Разные движки TeX: изучение их поддержки цветных шрифтов OpenType и выбор того, какой движок TeX использовать.
* API HarfBuzz в LuaHBTeX: введение в «магию» [формирования текста](#the-concept-of-text-shaping) в LuaHBTeX.

### Три способа набора цветных эмодзи

Цветные эмодзи можно набирать в LaTeX тремя основными способами:

1. Используя стандартные инструменты графики LaTeX, такие как TikZ, MetaPost или Asymptote, для рисования эмодзи.
2. Вставляя эмодзи с помощью заранее подготовленных графических файлов эмодзи, хранящихся во внешних файлах.
3. Рассматривая эмодзи как текст, закодированный в Unicode, и используя [формирования текста](#the-concept-of-text-shaping) с [цветные шрифты OpenType](#opentype-color-fonts) для их набора.

Практические варианты включения цветных эмодзи в документ LaTeX зависят от используемого для компиляции движка TeX, то есть от того, используете ли вы:

* pdfLaTeX: движок pdfTeX + LaTeX;
* XeLaTeX: движок XeTeX + LaTeX;
* LuaLaTeX: движок LuaHBTeX (начиная с TeX Live 2020) + LaTeX.

Все три этих движка TeX могут использовать инструменты или пакеты LaTeX для рисования эмодзи или использовать `\includegraphics{...}` для вставки эмодзи, хранящихся во внешних графических файлах. Рисование или импорт графики — идеальные способы набора эмодзи, когда вам нужно решение, не зависящее от движка TeX, используемого для компиляции документа LaTeX.

Однако если ваш рабочий процесс позволяет выбрать конкретный движок TeX, и вы предпочитаете использовать цветные шрифты OpenType и обработку текста на основе Unicode, вам нужна новейшая версия LuaTeX, называемая LuaHBTeX. Начиная с TeX Live 2020, LuaHBTeX используется для компиляции документов LaTeX на основе формата LuaLaTeX.

## Справка по Unicode и символам эмодзи

### Кодировки символов

Компьютеры хранят, передают и обрабатывают текст с помощью последовательности числовых (целочисленных) значений, которые представляют составляющие текста *символы*. Надёжная обработка текста требует, чтобы производители и потребители текста договорились о том, какие целочисленные значения следует использовать для представления отдельных символов внутри потока текста. Иными словами, какова *символ* *кодировка* ? Кодировка — это набор согласованных целочисленных значений, назначенных для представления определённого набора символов: каждый символ представляется целочисленным значением в пределах используемой кодировки.

### И тут появляется Unicode

Исторически, в эпоху 8-битного текста использовались многие разные кодировки символов, и всегда возникала угроза *несоответствия кодировок*: производители и потребители текста ошибочно предполагают разные кодировки, что приводит к ошибкам обработки текста. Любой, кто уже несколько лет работает с TeX/LaTeX, вероятно, сталкивался с несоответствиями кодировок между входным текстом и шрифтами, используемыми для набора документа. Если шрифты документа настроены на кодировку, отличную от кодировки текста, это, скорее всего, приводит к отсутствующим или ошибочным символам в сверстанном PDF.

Эти исторические проблемы с кодировками можно решить с помощью международного стандарта, кодирующего все символы мира: Unicode. Стандарт Unicode не статичен, а периодически обновляется, чтобы включать дополнительные символы и письменности (системы письма) в свою схему кодирования. Существует [формальный процесс рассмотрения предложений о новых символах](http://www.unicode.org/pending/proposals.html) с конкретной [схемой для новых символов эмодзи](https://www.unicode.org/emoji/proposals.html).

### Сколько символов Unicode?

Unicode кодирует теоретический максимум в 1 114 112 символов. Каждое из 1 114 112 целочисленных значений называется *кодовой точкой*: целочисленным значением, присвоенным для идентификации каждого символа. Однако по различным техническим причинам только [1 112 064 кодовые точки](https://en.wikipedia.org/wiki/Unicode#Architecture_and_terminology) могут быть назначены реальным символам: 2048 кодовых точек не назначаются и запрещены к использованию в тексте, совместимом с Unicode.

На момент написания (первая версия этой статьи) версия 13 стандарта Unicode выделяла в общей сложности 143 859 кодовых точек реальным символам, включая [3304 символа, теперь закодированных как эмодзи](https://www.unicode.org/L2/L2020/20114r-family-emoji-explor.pdf) (см. страницу 2 того документа). Рост числа символов, кодируемых Unicode, хорошо документирован в статье [Сколько символов Unicode существует?](https://www.babelstone.co.uk/Unicode/HowMany.html) и в [статье в Википедии](https://en.wikipedia.org/wiki/Unicode#Versions).

### плоскости Unicode

Вся совокупность из 1 114 112 кодовых точек Unicode разделена на 17 так называемых плоскостей: Плоскость 0 до Плоскости 16, каждая из которых содержит 65 536 значений кодовых точек, что даёт в общей сложности $$17\times2^{16} = 1,114,112$$ символов. Плоскость 0, называемая [Основной многоязычной плоскостью](https://en.wikipedia.org/wiki/Plane_\(Unicode\)#Basic_Multilingual_Plane), кодирует наиболее часто используемые символы. Плоскости 1–16 называются [дополнительными плоскостями](http://unicode.org/glossary/#supplementary_planes).

### Появление эмодзи

Новые символы возникают по мере изменения способов человеческого общения, и технология мобильных телефонов породила один такой набор символов: эмодзи, которые развивались в Японии в конце 1990-х годов. Неудивительно, что [FAQ Unicode по эмодзи](https://unicode.org/faq/emoji_dingbats.html) отмечает

> «Слово emoji происходит от японских [絵](http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=%E7%B5%B5) (e ≅ картинка) + [文字](http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=%E6%96%87) (moji ≅ письменный символ).»

Читателям, интересующимся происхождением и историческим развитием эмодзи, может быть интересен этот [вводный материал по Unicode](https://unicode.org/reports/tr51/#Introduction) или статья [I second that emoji: стандарты, структуры и социальное производство emoji](https://firstmonday.org/ojs/index.php/fm/article/view/9381).

Лишь в 2010 году, с выпуском [версии 6.0 стандарта Unicode](https://www.unicode.org/versions/Unicode6.0.0/), многие эмодзи были официально признаны *символы* сами по себе. Unicode 13.0 закодировал [3304 символа как эмодзи](https://www.unicode.org/L2/L2020/20114r-family-emoji-explor.pdf) (см. страницу 2 того документа), а в Unicode 13.1 перечислены [3521 эмодзи](https://unicode.org/emoji/charts/emoji-counts.html).

### Эмодзи живут на более высокой плоскости

Unicode назначил многим символам эмодзи кодовые точки за пределами Основной многоязычной плоскости (BMP), закодированные [в Плоскости 1](https://en.wikibooks.org/wiki/Unicode/Character_reference/1F000-1FFFF) с кодовыми точками в диапазоне 1F000–1FFFF — что имеет важное последствие для всех, кто хочет *копировать и вставлять* символы эмодзи в редакторы Overleaf (Code Editor или Visual Editor). Текстовые редакторы Overleaf могут обрабатывать только символы внутри Основной многоязычной плоскости, хотя мы надеемся, что будущие обновления добавят поддержку символов вне BMP. Учтите, что это ограничение затрагивает только символы вне BMP внутри текста, вставленного в файлы, предназначенные для редактирования через редакторы Overleaf. Есть и другие способы доступа к символам эмодзи:

* Используя примитивные команды `\char"<кодовая точка>` или `\Uchar"<кодовая точка>` (см. [этот раздел](#optional-detail-luatexluahbtex-char-vs-uchar) статьи).
* Используя входные текстовые файлы, содержащие символы эмодзи в формате UTF-8.
* Используя команды LaTeX (макросы), которые вставляют символы эмодзи.

#### Вставка эмодзи и других символов вне BMP в Overleaf

Если вы вставите символ эмодзи, например 😀, в Overleaf Code Editor, он в настоящее время будет преобразован в символы ��.

![Ошибка при копировании и вставке символов вне BMP в редакторы Overleaf](/files/e628cd81db177f6e64807852a63e2e6b2ff91107)

Символ � имеет кодовую точку Unicode FFFD, и его официальное название — REPLACEMENT CHARACTER; он используется для «[замены неизвестного, нераспознанного или не представимого символа](https://en.wikipedia.org/wiki/Specials_\(Unicode_block\))».

### Использование кодовых точек Unicode (U+) в LuaLaTeX

Документация Unicode представляет значения кодовых точек с помощью записи `U+<шестнадцатеричное значение>`— такие как `U+1F600`, где `1F600` — это `<шестнадцатеричное значение>` кодовой точки Unicode для символа эмодзи 😀. Чтобы использовать эти значения кодовых точек в LuaLaTeX, нужно удалить `U+` и записать `\char"<шестнадцатеричное значение>` или `\Uchar"<шестнадцатеричное значение>`. `"` символ сообщает движку TeX, что указанное число задано в шестнадцатеричной системе. Например, чтобы использовать эмодзи 😀, вы бы написали `\char"1F600` или `\Uchar"1F600`— используя шрифт, способный его набрать.

Минимальный пример LuaLaTeX с использованием `\char` и `\Uchar` для набора символа эмодзи 😀 может быть таким:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emojifont[Renderer=Harfbuzz]{NotoColorEmoji.ttf}
%Используйте \emojifont внутри группы, чтобы ограничить её действие локально
{\emojifont
\Uchar"1F600
\char"1F600}
\end{document}
```

[Откройте этот пример LuaLaTeX в Overleaf](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Test+using+LuaLaTeX\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%5BRenderer%3DHarfbuzz%5D%7BNotoColorEmoji.ttf%7D%0A%25Use+%5Cemojifont+in+a+group+to+keep+its+effects+local%0A%7B%5Cemojifont+%0A%5CUchar%221F600%0A%5Cchar%221F600%7D%0A%5Cend%7Bdocument%7D)

**(дополнительная деталь) LuaTeX/LuaHBTeX: \char против \Uchar**

Помимо обычной `\char<код символа>` команды для набора определённого `<код символа>`, при использовании текущего шрифта движки LuaTeX, LuaHBTeX и XeTeX также предоставляют `\Uchar<код символа>` команду. С точки зрения пользователя результат `\char` и `\Uchar` выглядит одинаково, но есть тонкое различие в том, как работают эти команды, как мы отметим ниже.

**Ключевое различие: разворачивание**

`\Uchar` — так называемая [разворачиваемая команда](/latex/ru/podrobnye-stati/22-how-does-expandafter-work-the-meaning-of-expansion.md#expansion-a-general-term-for-a-set-of-operations) тогда как `\char` — нет. Когда `\char<код символа>` или `\Uchar<код символа>` команда «выполняется», то есть команда не сохраняется как часть макроса или другого списка токенов, внутри движка TeX происходят следующие действия:

* **`\char<код символа>`** приказывает движку TeX немедленно вставить токен символа, представляющий `<код символа>`, в тот фрагмент содержимого, который он в данный момент набирает.
* В отличие от этого, **`\Uchar<код символа>`** имеет два отдельных этапа обработки:

1. Это `\Uchar<код символа>` команда *развёрнут*разворачивается, и `<код символа>` преобразуется во временный список токенов, содержащий один [символьным токеном](/latex/ru/podrobnye-stati/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md#tex-tokens-101-28and-notions-of-expansion29) который представляет `<код символа>`.
2. этот однобуквенный список токенов теперь *становится доступным* для движка TeX как источник его следующего входного элемента. По сути, движок TeX «временно переводит взгляд», используя этот список из одного токена как место своего следующего входного элемента (токена). По умолчанию движок TeX просто возвращается, чтобы прочитать (ввести) этот токен и набрать соответствующий символ, воспроизводя поведение `\char` команды. **Однако**, поскольку этот `<код символа>` не был немедленно набран, а был временно *хранятся* (сохранён) как один токен, примитивные команды TeX или макросы LaTeX могут использовать (поглощать) этот токен — его не обязательно сразу набирать, но можно использовать в дальнейшей обработке по мере необходимости.

По сути, `\char<код символа>` говорит «наберите этот `<код символа>` сейчас», тогда как `\Uchar<код символа>` имеет форму «отложенного действия», создавая сохранённый токен символа и делая его доступным как следующий входной элемент (токен). Этот токен может либо быть использован (поглощён) командами и макросами TeX, либо повторно прочитан движком TeX и набран.

### Unicode (кодировка) — это ещё не вся история

Возможность использовать символы эмодзи внутри текста, закодированного в Unicode, — лишь часть истории успеха эмодзи. Рост использования эмодзи также стал возможен благодаря развитию [технологии шрифтов OpenType](https://learn.microsoft.com/en-us/typography/opentype/)— шрифтов, чьи глифовые данные (дизайн символов) могут содержать [цветовые данные](https://learn.microsoft.com/en-us/typography/opentype/spec/colr): так называемые [цветные шрифты OpenType](#opentype-color-fonts).

Помимо подходящих шрифтов, использование цветных эмодзи требует дополнительных программных компонентов, задачи которых включают:

* предварительную обработку («[формирование](#the-concept-of-text-shaping)») текста, закодированного в Unicode, *подготовку* его для отображения с использованием определённого шрифта;
* *рендеринг и отображение* цветных эмодзи шрифта *глифов* на экран устройства.

#### Глиф и символ: разве это не одно и то же?

Термины «глиф» и «символ» часто используются так, будто они взаимозаменяемы — как будто обозначают одно и то же базовое понятие — но между ними есть тонкая, хотя и важная, разница.

Unicode [определяет термин «символ»](http://www.unicode.org/glossary/#character) как:

> «Наименьшая составляющая письменного языка, имеющая семантическую ценность; относится к абстрактному значению и/или форме, а не к конкретной форме… »

В отличие от этого, «глиф» — это *конкретный* *форма* (дизайн) для *визуального представления* определённого *символ*.

Проблему символа и глифа легко заметить, когда текст, насыщенный эмодзи, просматривается в различных программных системах/платформах, например если читать один и тот же текст на мобильном телефоне под управлением iOS или Android либо на настольном компьютере Windows. Какое бы устройство или платформа ни использовались, базовый текст (последовательность символов) будет содержать тот же закодированный в Unicode *эмодзи* *символы*. Именно возможности конкретного устройства, связанные с *предварительной обработкой* этого текста, а затем *рендерингом* и *отображаемый* результатов, возможно с использованием шрифтов, специфичных для устройства, и создают разные глифы (дизайны символов) для представления одних и тех же символов эмодзи.

Полный список эмодзи [Unicode](https://unicode.org/emoji/charts/full-emoji-list.html) содержит примерные изображения, представляющие каждый символ эмодзи Unicode, демонстрируя различные глифы, используемые разными технологическими вендорами. Не только дизайнеры шрифтов создают собственные особые дизайны (глифы) для представления символов эмодзи, но и отдельные шрифты различаются по числу поддерживаемых ими символов эмодзи (для которых у них есть глифы), а также могут содержать или не содержать более продвинутые функции обработки текста с эмодзи, включённые в спецификации эмодзи Unicode.

Понятие и концепция символов, их семантика и кодировка составляют основу мира Unicode: он работает именно с символами. Дизайн и визуальное представление отдельных символов как глифов относятся к технологиям шрифтов и к ремеслу дизайна шрифтов.

#### Эмодзи Unicode: гораздо больше, чем кодирование текста

Ключевая роль Unicode — предоставить глобальный стандарт кодирования, который определяет, какое целочисленное значение, называемое *кодовой точкой,* следует использовать для представления каждого символа, включая эмодзи, внутри потока текста, закодированного в Unicode.

Спецификация Unicode для эмодзи также определяет *поведение обработки* для определённых *последовательности* эмодзи-символов, присутствующих в потоке текста, закодированного в Unicode. Определённые последовательности эмодзи могут быть «объединены» в процессе, называемом [формирования текста](#the-concept-of-text-shaping) для получения одного результирующего («составного») глифа эмодзи — этот единый глиф будет использоваться операционной системой устройства для представления исходной последовательности символов, присутствующей в тексте.

Технический отчёт Unicode по [эмодзи Unicode](https://unicode.org/reports/tr51/) документирует богатый набор возможностей, доступных программному обеспечению, которое хочет обеспечивать обработку символов эмодзи в соответствии с Unicode. Например, Unicode определяет (кодирует) символы, называемые [модификаторами эмодзи](http://www.unicode.org/reports/tr51/#Emoji_Modifiers_Table) которые можно использовать для создания *вариаций* «базовых» символов эмодзи, таких как вариации [оттенка кожи на основе шкалы Фицпатрика](http://www.unicode.org/reports/tr51/#Diversity). Учтите, что набор базовых символов эмодзи и применимые модификаторы определяются как часть общего [стандарта эмодзи Unicode](http://www.unicode.org/reports/tr51).

Страница Unicode [Последовательности эмодзи](http://unicode.org/emoji/charts/emoji-sequences.html) предоставляет таблицу последовательностей, которые в настоящее время описаны спецификацией Unicode. Наведите указатель мыши на любое из изображений глифов эмодзи, чтобы увидеть небольшую всплывающую подсказку с последовательностью символов эмодзи Unicode, которая создаёт этот глиф:

![EmojiSequenceChart.png](/files/ebe0ea7473e26c1f63fa821d94a781d0b60d6911)

Например, глиф эмодзи:

![HandMediumSkinTone.png](/files/763942e92a587fe1e711c4666466acd8188d25ae)

перечислен в разделе [последовательностей модификаторов](http://unicode.org/emoji/charts/emoji-sequences.html#modifier_sequences) и создаётся двухсимвольной последовательностью U+1F44B U+1F3FD. Эти составные символы:

U+1F44B:![UnicodeWavingHandDefault.png](/files/58bd1a744e072933c96c31fd6bc3618aef0ad8fc) (МАХАЮЩАЯ РУКА)

U+1F3FD:![FitzPatrick3.png](/files/e017767c3896935f721923f46cf8d13422617361) (МОДИФИКАТОР ЭМОДЗИ FITZPATRICK TYPE-4)

**Использование модификаторов тона кожи в LuaHBTeX**

В следующем примере используется LuaHBTeX для демонстрации использования модификаторов эмодзи:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emojifont[Renderer=HarfBuzz,SizeFeatures={Size=20}]{NotoColorEmoji.ttf}
Изолированная машущая рука: {\emojifont\Uchar"1F44B}\par
Изолированный модификатор: {\emojifont\Uchar"1F3FD}\par
Результат объединения: {\emojifont\Uchar"1F44B\Uchar"1F3FD}
\end{document}
```

[Откройте этот пример с модификаторами эмодзи LuaLaTeX в Overleaf](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Emoji+modifiers+using+LuaLaTeX\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%5BRenderer%3DHarfBuzz%2CSizeFeatures%3D%7BSize%3D20%7D%5D%7BNotoColorEmoji.ttf%7D%0AIsolated+waving+hand%3A+%7B%5Cemojifont%5CUchar%221F44B%7D%5Cpar%0AIsolated+modifier%3A+%7B%5Cemojifont%5CUchar%221F3FD%7D%5Cpar+%0ACombined+result%3A+%7B%5Cemojifont%5CUchar%221F44B%5CUchar%221F3FD%7D%0A%5Cend%7Bdocument%7D)

Этот пример выдаёт следующий результат:

![ModifiersInLuaHBTeX.png](/files/fdf2478dda54e2aff716d290ff934e18c0a67feb)

#### UTF-8: его роль в хранении текста Unicode

Любой текст или код, который вы вводите или вставляете в Code Editor Overleaf (или Visual editor), будет храниться в формате UTF-8, поэтому мы кратко рассмотрим, что же на самом деле означает UTF-8. UTF означает Unicode Transformation Format, а роль UTF-8 в хранении или передаче текста, закодированного в Unicode, подчёркивается фразой «Transformation *Format*».

Значения кодовых точек Unicode находятся в диапазоне от 0 до максимума 1 114 111, поэтому невозможно представить все значения символов Unicode с помощью одного 8-битного байта, который может хранить только до 256 различных значений: от 0 до 255. Однако любое целочисленное значение кодовой точки Unicode можно представить с помощью *непрерывной последовательности* байтовых значений — именно в этом и состоит принцип UTF-8.

UTF-8 предоставляет «рецепт» для *преобразования* (то есть «кодирования» или «конвертации») целочисленного значения кодовой точки Unicode в уникальную последовательность из 1–4 подряд идущих байтовых целых чисел: число подряд идущих байтов, которое требуется, зависит от значения целого числа кодовой точки. Поэтому можно встретить описание UTF-8 как хранения символов Unicode в виде *многобайтовых последовательностей* поскольку один символ Unicode (целое значение кодовой точки) представляется в UTF-8 как последовательность из 1–4 подряд идущих байтов.

Естественно, текст, сохранённый в UTF-8, можно преобразовать обратно в исходную последовательность целочисленных значений кодовых точек Unicode — именно это должны делать XeTeX или LuaTeX/LuaHBTeX при чтении входного файла LaTeX, сохранённого в формате UTF-8. Эти движки TeX должны знать входные значения кодовых точек Unicode (символов), прежде чем смогут набирать текст. Учтите, что pdfTeX не имеет встроенной поддержки декодирования UTF-8, поэтому ему приходится полагаться на макросы TeX для обработки (декодирования) входного текста, отформатированного в UTF-8.

**Несколько примеров UTF-8**

* Арабский символ ش («шин») имеет кодовую точку Unicode 0634 в шестнадцатеричной системе (основание 16) или 1588 в десятичной системе (основание 10). В UTF-8 ش представлен 2 (шестнадцатеричными) значениями D8 и B4, так что символ ش хранится как два последовательных байта D8B4 в тексте, закодированном в UTF-8.
* Символ эмодзи 😀 имеет кодовую точку Unicode 1F600 в шестнадцатеричной системе (основание 16) или 128512 в десятичной системе (основание 10). В UTF-8 😀 представлен 4 (шестнадцатеричными) значениями F0, 9F, 98 и 80, так что символ 😀 хранится как 4 последовательных байта F09F9880 в файле текста UTF-8.

#### Специальные символы, используемые в обработке текста эмодзи на основе Unicode

Не каждый символ, закодированный в Unicode, предназначен для визуального отображения с помощью глифов шрифта: некоторые закодированные символы обозначаются как *непечатаемые символы* чьё назначение — помогать специализированным функциям обработки текста (в поддерживающем программном обеспечении). Разные программные приложения обеспечивают разный уровень поддержки непечатаемых символов, закодированных в Unicode, поэтому результат будет зависеть от используемой программной среды — приложений и шрифтов.

**Два непечатаемых символа, о которых стоит знать**

* **Соединитель нулевой ширины (ZWJ)**, кодовая точка 200D (шестнадцатеричная), как следует из названия, предназначен для вызова «поведения соединения» входных символов — но только если эти входные символы *обладают* определённым поведением соединения.
* **Разъединитель нулевой ширины (ZWNJ)**, кодовая точка 200C (шестнадцатеричная), предназначен для *предотвратить* «поведения соединения», которое могли бы иначе проявлять входные символы. Например, ZWNJ можно использовать, чтобы предотвратить поведение соединения у последовательных арабских символов, которые обычно обрабатывались бы (формировались бы) в соединительные формы.

Unicode опубликовал список [рекомендуемых последовательностей эмодзи с ZWJ](https://unicode.org/emoji/charts/emoji-zwj-sequences.html) которые используют U+200D ZERO WIDTH JOINER (ZWJ) для объединения последовательностей символов эмодзи в единый составной глиф эмодзи — если он доступен в используемом шрифте(ах).

**Пример использования разъединителя нулевой ширины**

Следующий минимальный фрагмент кода использует шрифт Scheherazade OpenType, включённый в TeX Live, для определения шрифта LaTeX под названием `\arabicfont` который мы можем использовать для набора арабского текста. Строка

```latex
{\arabicfont Non-joining:\textdir TRT\Uchar"0644\Uchar"200C\Uchar"0627}
```

использует символ разъединителя нулевой ширины через `\Uchar"200C`, чтобы предотвратить обычное поведение соединения двух арабских букв ل (лам) и ا (алиф). Обратите внимание на использование `\textdir TRT` для задания направления текста справа налево:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\arabicfont[Script=Arabic,Renderer=Harfbuzz,SizeFeatures={Size=40}]{Scheherazade}
{\arabicfont Joining:\textdir TRT\Uchar"0644\Uchar"0627}\par
{\arabicfont Non-joining:\textdir TRT\Uchar"0644\Uchar"200C\Uchar"0627}
\end{document}
```

[Откройте этот пример LuaLaTeX в Overleaf](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Zero+width+non-joiner+using+LuaLaTeX\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Carabicfont%5BScript%3DArabic%2CRenderer%3DHarfbuzz%2CSizeFeatures%3D%7BSize%3D40%7D%5D%7BScheherazade%7D%0A%7B%5Carabicfont+Joining%3A%5Ctextdir+TRT%5CUchar%220644%5CUchar%220627%7D%5Cpar%0A%7B%5Carabicfont+Non-joining%3A%5Ctextdir+TRT%5CUchar%220644%5CUchar%22200C%5CUchar%220627%7D%0A%5Cend%7Bdocument%7D)

Этот пример выдаёт следующий результат:

![NonJoiner.png](/files/93f01b892cdf99fa127ea9d38d602f2c04d1a98e)

## Понятие «формирования текста»

Начнём с визуального примера, используя перевод слова «educational» на урду. Текст перевода на урду можно ввести с клавиатуры или сенсорного устройства, и он будет создан как простая линейная последовательность арабских символов Unicode. Однако когда этот текст набирается или отображается на экране устройства в [стиле насталик](https://en.wikipedia.org/wiki/Nastaliq)результатом становится сложная двумерная композиция глифов.

Используя наш пример с урду, следующая графика сравнивает линейный ввод арабского текста Unicode *символы* с набором в стиле насталик, состоящим из двумерного расположения *глифов* присутствующих в (бесплатном) шрифте [Awami Nastaliq](https://software.sil.org/awami/download/):

![](/files/4bbbc834b78395209ce9cd387774140f4613dfef)

Процесс «перевода» входных символов в набор правильно расположенных выходных глифов называется *формирования текста*, и он является важнейшим компонентом обработки текста перед его отображением или набором. В нашем примере использовался текст на языке урду (арабская письменность), потому что результат формирования текста там особенно очевиден, в отличие от языков, использующих латиницу, таких как английский, где формирование выражено гораздо слабее — например, при создании простых лигатур.

Формирование текста необходимо при использовании письменностей (систем письма), таких как [Арабский](https://en.wikipedia.org/wiki/Arabic), [иврит](https://en.wikipedia.org/wiki/Hebrew_language), [деванагари](https://en.wikipedia.org/wiki/Devanagari) или [Малаялам](https://en.wikipedia.org/wiki/Malayalam), лишь четыре примера так называемых *сложных письменностей*. Чтобы обеспечить корректное отображение текста на этих письменностях и в языках, которые их используют, процесс формирования должен тщательно учитывать любые правила и особенности формирования, присутствующие в конкретном сочетании письменности и языка. Например, некоторые языки требуют, чтобы несколько входных символов создавали один определённый выходной глиф, либо могут существовать сложные требования к аккуратному размещению диакритических знаков и к перестановкам между глифами, чтобы отдельные глифы были позиционированы правильно относительно друг друга.

В общем случае для формирования фрагмента текста требуется несколько видов информации:

* Письменность или *письменности* на котором написан текст.
* Конкретный *языка* используемый. Отдельные письменности могут использоваться для нескольких языков, при этом каждая комбинация письменности и языка имеет свои особенности и нюансы формирования.
* Письмо *направление* текста — например, справа налево или слева направо.
* Один *шрифт* который предоставляет глифы, необходимые для представления сформированного текста, и, при необходимости, содержит дополнительные «правила формирования», которые направляют процесс формирования текста.

Требования к формированию текста, особенно для сложных письменностей и связанных с ними языков, могут быть чрезвычайно детальными и тонкими, что указывает на необходимость специализированного программного обеспечения, которое может применять потенциально очень сложные «правила» формирования текста. Неудивительно, что такое ПО существует и называется *движок формирования текста*; тот, который мы будем обсуждать, называется [HarfBuzz](https://en.wikipedia.org/wiki/HarfBuzz), документацию которого стоит прочитать — например [Зачем мне нужен движок формирования?](https://harfbuzz.github.io/why-do-i-need-a-shaping-engine.html).

**Дополнительные материалы о формировании текста**

Эти короткие введения настоятельно рекомендуются:

* [Что такое формирование текста?](https://harfbuzz.github.io/what-is-harfbuzz.html#what-is-text-shaping)
* [Зачем мне нужен движок формирования?](https://harfbuzz.github.io/why-do-i-need-a-shaping-engine.html)

**Техническая заметка TeX: несколько технологий формирования (моделей)**

Движок формирования текста HarfBuzz поддерживает несколько «технологий формирования», которые различаются тем, как они реализуют процесс формирования, — каждая реализация называется *шейпером*, в том числе в `luaotfload` документации. Основное внимание в этой статье уделяется формированию OpenType, но альтернативной, бесплатной для использования технологией является [Graphite](https://scripts.sil.org/cms/scripts/page.php?site_id=projects\&item_id=graphite_aboutOT), разработанная [SIL International](https://www.sil.org/). Ещё одной моделью формирования, поддерживаемой HarfBuzz, является [Apple Advanced Typography (AAT)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html)— шрифты, поддерживающие AAT, обычно используются на технологических платформах Apple.

**Пример использования шейпера Graphite**

В следующем примере набирается некоторый текст на урду с использованием шрифта под названием [Awami Nastaliq](https://software.sil.org/awami/download/), который поддерживает формирование Graphite и доступен на Overleaf. Awami Nastaliq создан [SIL International](https://www.sil.org/), организацией, отвечающей за разработку технологии Graphite.

Следующий пример демонстрирует расширенные возможности формирования шрифтов на основе Graphite — обратите внимание, как `luaotfload` объявление шрифта выбирает формирование Graphite с помощью `shaper=graphite2`.

```latex
\documentclass{article}
\usepackage{luaotfload}
\begin{document}

\font\urdutest={file:AwamiNastaliq-Regular.ttf:mode=harf;shaper=graphite2} at 100bp
% Технологии
\pardir TRT\textdir TRT \urdutest ٹیکنالوجی

\vskip 75bp

% Образование
\pardir TRT\textdir TRT \urdutest تعلیمی
\end{document}
```

[Откройте этот пример в Overleaf.](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Typesetting+Urdu+using+the+Graphite+shaper\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bluaotfload%7D%0A%5Cbegin%7Bdocument%7D%0A%0A%5Cfont%5Curdutest%3D%7Bfile%3AAwamiNastaliq-Regular.ttf%3Amode%3Dharf%3Bshaper%3Dgraphite2%7D+at+100bp%0A%25+Technology%0A%5Cpardir+TRT%5Ctextdir+TRT+%5Curdutest+%D9%B9%DB%8C%DA%A9%D9%86%D8%A7%D9%84%D9%88%D8%AC%DB%8C%0A%0A%5Cvskip+75bp%0A%0A%25+Educational%0A%5Cpardir+TRT%5Ctextdir+TRT+%5Curdutest+%D8%AA%D8%B9%D9%84%DB%8C%D9%85%DB%8C%0A%5Cend%7Bdocument%7D)

Этот пример выдаёт следующий результат:

![](/files/0cb1dd6deabf83913a7dd442f18b56a5f9f39b44)

#### Эмодзи и формирование текста

Формирование текста было представлено на примерах языка со сложной письменностью — урду. Однако может удивить, что для отображения правильных глифов эмодзи требуется применять формирование текста к Unicode-тексту, содержащему последовательности символов эмодзи —[как отметил ведущий разработчик HarfBuzz](https://github.com/harfbuzz/harfbuzz/issues/2428#issuecomment-639108677):

> ...формирование эмодзи с помощью HarfBuzz полностью входит в его задачу и на самом деле необходимо для получения семейных эмодзи, оттенков кожи и т. д.

Мы рассмотрим примеры этого.

### Разделение ответственности: движок формирования текста + шрифты OpenType

На практике формирование текста — это «совместная операция», или разделение труда, между логикой и правилами, встроенными в движок формирования текста, и дополнительными правилами и данными формирования, встроенными в используемый(ые) шрифт(ы) — далее мы рассматриваем только формирование на основе OpenType *только*.

Для выполнения формирования движку формирования текста обычно подают некоторый Unicode-текст, указанную письменность и язык, возможно, направление письма, и, что наиболее важно, шрифт OpenType для использования в процессе формирования — шрифт предоставит результат: набор глифов и данные позиционирования. Если требуется, движок формирования может применять дополнительные правила ([функции OpenType](https://en.wikipedia.org/wiki/List_of_typographic_features#OpenType_typographic_features)) содержащиеся в используемом шрифте OpenType — какие правила применять, обычно выбирает пользователь из списка функций, поддерживаемых шрифтом.

Результатом процесса формирования является *список глифов* содержащихся в шрифте OpenType, вместе с *межглифовыми* данными позиционирования. Эти данные относятся к *относительному размещению сформированных глифов*; они не относятся к абсолютному позиционированию на набранной странице или в другом носителе/контенте, таком как веб-страница, твит и т. д. Программное обеспечение для рендеринга (система верстки, веб-браузер и т. д.) использует информацию о межглифовом позиционировании, чтобы обеспечить правильное взаимное расположение глифов после их сборки и включения в конечный вывод.

#### Что такое список глифов?

Внутри шрифта OpenType каждому глифу присваивается числовой идентификатор, целочисленное значение, называемое индексом глифа — также называемым идентификатором глифа или GID. После завершения задачи формирования движок формирования вернёт результаты в виде *списка идентификаторов глифов* плюс *данные позиционирования* для этих глифов.

Отдельным глифам в шрифтах OpenType создатель шрифта назначает индексы (идентификаторы), что делает это значение сильно зависящим от конкретного шрифта и произвольным — оно также может различаться между версиями одного и того же шрифта. Никогда не следует предполагать, что одно и то же значение GID будет применимо к «похожим» глифам в разных шрифтах; почти наверняка это не так. Если у вас есть список идентификаторов глифов, предоставленный движком формирования, вы можете использовать их только для доступа к глифам в том шрифте, из которого они были получены.

#### Что такое шрифты OpenType?

В интернете *полно* объяснений и подробностей о шрифтах OpenType, поэтому мы ограничимся кратким описанием.  [спецификация OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/) — это сложный документ, предназначенный для разработчиков, но по сути он определяет формат файла, или контейнер, для данных шрифта. Шрифт OpenType содержит данные, описывающие формы глифов, вместе с информацией о поддерживаемой(ых) письменности(ях) и языке(ах), метаданными о шрифте и различными «таблицами», которые определяют [типографические функции](https://en.wikipedia.org/wiki/List_of_typographic_features#OpenType_typographic_features) поддерживаемые шрифтом.

Движок формирования текста обычно можно заставить избирательно применять (использовать) функции шрифта в процессе формирования, применяя определённые типографические эффекты («правила»), которые выбирают подходящий набор глифов, содержащихся в шрифте. Выбранный шрифт должен поддерживать и предоставлять глифы для любых функций, которые движку формирования текста будет предложено применить.

#### Кодированные и некодированные «глифы»

Шрифты OpenType включают таблицу данных под названием [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap) (сопоставление символов с индексами глифов), которая сопоставляет набор символов Unicode, поддерживаемых шрифтом, соответствующему индексу глифа в этом шрифте. Следующее видео даёт краткий взгляд на таблицу cmap, содержащуюся в шрифте под названием `lmmono10-regiular.otf` (входит в состав TeX Live).

{% embed url="<https://videos.ctfassets.net/nrgyaltdicpt/2537Y9gOUMWgd0t1guqt0X/482c53a9d8112ecae3d622aa7e00eef8/openType_cmap.mp4>" %}

Однако шрифты обычно содержат множество глифов, которые не представляют конкретный символ Unicode и не включены в таблицу cmap. Следовательно, набор глифов, присутствующих в шрифте OpenType, можно разделить на два основных набора:

* кодированные глифы, представляющие символы Unicode;
* некодированные глифы, не представляющие символы Unicode.

К кодированным глифам можно получить доступ, включив в текст соответствующий символ Unicode — но как насчёт некодированных глифов, как они используются/доступны? Эти глифы обычно используются для выдачи результата операций формирования текста, включая применение функций шрифта для создания определённых визуальных/типографических эффектов.

### цветные шрифты OpenType

Ожидается, что символы эмодзи будут отображаться в полном цвете — чёрно-белые эмодзи не совсем дают «полноценный опыт эмодзи». Однако на момент первоначального кодирования эмодзи в Unicode, [спецификация шрифтов OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/) не предусматривала подходящих средств для внедрения *цветных*-глифовых данных в шрифты OpenType. Этот «пробел» в OpenType побудил ведущих поставщиков технологий/платформ искать решения, и последовавшая «гонка» привела к [различным предложениям по расширению OpenType](https://www.fontlab.com/news/color-font-format-proposals/) для поддержки цветных шрифтов OpenType — не только для отображения цветных символов эмодзи (глифов), но и для отображения любого глифа в цвете.

#### Четыре варианта цветных шрифтов OpenType

[Adobe, Microsoft, Google и Apple представили свои предложения](https://www.fontlab.com/news/color-font-format-proposals/) по расширению OpenType для поддержки полноцветных шрифтов OpenType, и в конечном итоге четыре предложения были приняты и включены в официальную спецификацию OpenType. Для удобства мы можем условно сгруппировать эти четыре варианта в векторные и растровые, но, как показано в этом [Репозиторий GitHub](https://github.com/simoncozens/test-fonts), спецификация OpenType достаточно гибка, чтобы поддерживать файлы цветных шрифтов OpenType, сочетающие эти четыре базовые технологии.

* **Векторные шрифты OpenType:**
* **Microsoft**: формы глифов описываются с помощью формы многослойных цветовых векторов ([COLR](https://docs.microsoft.com/en-us/typography/opentype/spec/colr) и [CPAL](https://docs.microsoft.com/en-us/typography/opentype/spec/cpal) таблиц).
* [**Adobe и Mozilla**](https://www.w3.org/2013/10/SVG_in_OpenType/) ([таблица SVG](https://docs.microsoft.com/en-us/typography/opentype/spec/svg)): формы глифов рисуются с использованием SVG, который поддерживает глифы, построенные из векторов *и растровых изображений*. См. также [Руководство пользователя Adobe по шрифтам SVG](https://helpx.adobe.com/fonts/user-guide.html/fonts/using/ot-svg-color-fonts.ug.html).
* **Растровые шрифты OpenType:**
* **Google**: глифы представлены цветными PNG-изображениями, встроенными в шрифт ([CBDT](https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) и [CBLC](https://docs.microsoft.com/en-us/typography/opentype/spec/cblc) таблиц).
* **Apple**: глифы также представлены цветными изображениями, встроенными в шрифт. Помимо PNG, механизм Apple ([таблица sbix](https://docs.microsoft.com/en-us/typography/opentype/spec/colr)) также поддерживает JPEG и TIFF.

Как следствие, операционные системы и прикладное программное обеспечение, поддерживающие цветные шрифты OpenType, должны иметь дело с сегодняшним смешанным технологическим ландшафтом. Кроме того, следует учитывать, что отдельные цветные шрифты OpenType — и *версии* одного и того же шрифта — будут:

* иметь разное покрытие полного набора [символов Unicode эмодзи](https://unicode.org/emoji/charts/emoji-list.html)— то есть для скольких символов эмодзи шрифт предоставляет глифы;
* использовать разные дизайны глифов для представления отдельных символов эмодзи;
* различаться по функциям, которые они предоставляют для поддержки более продвинутых возможностей стандартов Unicode, таких как [модификаторами эмодзи](https://unicode.org/reports/tr51/#Emoji_Modifiers_Table)семейные эмодзи [Техническом стандарте Unicode № 51: Unicode Emoji](https://unicode.org/reports/tr51/).

#### Шумиха вокруг HarfBuzz

Мы уже упоминали о необходимости *движок формирования текста*: программного обеспечения, которое принимает некоторый входной Unicode-текст, написанный с использованием определённой комбинации письменности и языка, и, используя заданный шрифт, преобразует этот текст в последовательность глифов вместе с данными позиционирования, которые можно использовать для набора исходного входного текста.

[HarfBuzz](https://harfbuzz.github.io/) — один из таких движков формирования текста: это [библиотека с открытым исходным кодом](https://github.com/harfbuzz/harfbuzz) и результат более чем десятилетних исследований и разработки — и по-прежнему активно развивается и внедряется как часть многих программных продуктов. Сам HarfBuzz не выполняет «верстку», но предоставляет «сервисы формирования текста» программному обеспечению, которое решает интегрировать его, включая XeTeX, LuaHBTeX, [Adobe PhotoShop и Adobe InDesign](https://en.wikipedia.org/wiki/HarfBuzz).

Внедряя HarfBuzz, движки TeX могут воспользоваться его расширенными возможностями формирования текста для очень сложной многоязычной верстки, особенно для сложных письменностей, таких как арабская, иврит, деванагари и многие другие. Также отметим, что HarfBuzz используется для обработки и формирования текстовых символов Unicode эмодзи, что мы рассмотрим подробнее.

Следующая схема суммирует роль, которую HarfBuzz играет при интеграции с программным обеспечением, таким как XeTeX или LuaHBTeX, при наборе текста на сложной письменности, например арабской:

![Обзор формирования арабского текста с помощью HarfBuzz](/files/ca15c27ce62dc0820377c1dcf708ec8138228a2b)

**Изучаем HarfBuzz**

Любой, кто хочет узнать больше о HarfBuzz и сервисах формирования OpenType, которые он предоставляет XeTeX и LuaHBTeX, может [скачать двоичную сборку HarfBuzz](https://github.com/harfbuzz/harfbuzz/releases) которая содержит библиотеку HarfBuzz (для программистов) и утилиты командной строки `hb-view` и `hb-shape`.

**Пример: как использовать hb-view**

Создайте новый файл в вашем любимом текстовом редакторе с поддержкой UTF-8 и скопируйте/вставьте следующие шесть символов эмодзи 👋👋🏻👋🏼👋🏽👋🏾👋🏿 в этот текстовый файл, затем сохраните его в формате UTF-8 под именем, например, `emoji.txt`.

Обратите внимание, что ваш текстовый редактор может отображать (резервные) чёрно-белые версии эмодзи, потому что он не умеет (не запрограммирован) отображать цветные глифы. После сохранения этих 6 эмодзи файл `emoji.txt` должен содержать данные UTF-8 для следующей последовательности символов Unicode эмодзи — мы разделили модификаторы эмодзи запятыми исключительно для *удобства чтения*:

* `1F44B` для получения 👋
* `1F44B`, `1F3FB` для получения 👋🏻
* `1F44B`, `1F3FC` для получения 👋🏼
* `1F44B`, `1F3FD` для получения 👋🏽
* `1F44B`, `1F3FE` для получения 👋🏾
* `1F44B`, `1F3FF` для получения 👋🏿

В общей сложности должно быть **11** символов Unicode, каждый из которых генерирует 4 байта данных UTF-8, поэтому итоговый `emoji.txt` файл должен иметь размер 44 байта, не считая каких-либо маркеров конца строки, используемых в конце строки, содержащей эмодзи.

Это `hb-view` утилита может использовать файл `emoji.txt`, вместе с подходящим цветным шрифтом OpenType по вашему выбору, например `NotoColorEmoji.ttf`, чтобы сгенерировать SVG-файл результата формирования HarfBuzz. Следующий пример командной строки, который необходимо **ввести в одной строке** в вашем терминале, сгенерирует SVG-файл `emoji.svg`:

```latex
hb-view --font-size=20 --output-file=\"emoji.svg\"
--output-format=svg --text-file=emoji.txt
--font-file=NotoColorEmoji.ttf
```

При успешном выполнении файл `emoji.svg`, сгенерированный `hb-view`, можно открыть в Inkscape, и он должен выглядеть примерно так:

![Hbvieemoji.png](/files/ce5ebd5a2c6d9ca53f17ee98f2aebd74715a2b87)

`hb-view` можно использовать для изучения формирования HarfBuzz для любого подходящего файла Unicode-текста и шрифта OpenType — он, конечно, не ограничен использованием эмодзи! Введите

```latex
hb-view --help-all
```

чтобы увидеть множество параметров командной строки для этой мощной и удобной утилиты. Удачного формирования!

## Формирование текста и движки TeX

Здесь мы рассмотрим возможности формирования текста у XeTeX и семейства движков TeX LuaTeX.

### XeTeX

XeTeX был разработан в начале 2000-х и стал пионером нескольких инноваций в верстке на основе TeX, наиболее заметно *встроенная* поддержка:

* чтения Unicode-текста в формате UTF-8;
* использования шрифтов OpenType;
* формирования текста для многоязычной верстки;
* математической верстки на основе OpenType.

Способность XeTeX легко и удобно набирать языки со сложной письменностью обусловлена его встроенными возможностями формирования текста — первоначально основанными на ныне устаревшем [ICU LayoutEngine](http://userguide.icu-project.org/layoutengine). Благодаря работе Khaled Hosny XeTeX перешёл на использование HarfBuzz для формирования текста, как было отмечено в объявлении от [марта 2013 года](https://tug.org/pipermail/xetex/2013-March/024118.html). Для тех, кто хочет верстать многоязычный текст, XeTeX обычно называют движком TeX по выбору — но теперь есть и другой вариант, LuaHBTeX, который мы рассмотрим.

### LuaTeX и LuaHBTeX

Разработка LuaTeX началась примерно в 2005 году, но следовала философии проектирования, сильно отличающейся от XeTeX, который включал новые функции *непосредственно в* программное обеспечение XeTeX. В отличие от XeTeX, разработчики LuaTeX выбрали подход «...предоставить минимальный набор инструментов и никаких готовых решений». (см. [Reference Manual for LuaTeX](https://www.pragma-ade.com/general/manuals/luatex.pdf)). Вместо предоставления набора дополнительных функций *встроенных в* движков на базе LuaTeX внутренние механизмы движков LuaTeX раскрываются, чтобы разработчики и опытные пользователи могли использовать встроенный язык сценариев Lua для создания собственных решений.

Например, в отличие от XeTeX, движок LuaTeX не может *непосредственно* использовать шрифты OpenType; вместо этого шрифты OpenType должны загружаться и «подготавливаться к использованию» через функции загрузки шрифтов, написанные на Lua. Эти функции загрузки шрифтов называются *callback* функциями: кодом Lua, который LuaTeX вызовет («выполнит»), когда поступит запрос на загрузку шрифта.

Кроме того, движок LuaTeX не предоставляет никаких *встроенная* возможностей формирования текста — они тоже должны предоставляться внешним кодом, к которому движок LuaTeX может обращаться за услугами формирования текста. И снова это контрастирует с движком XeTeX, который включил возможности формирования текста в основное программное обеспечение.

#### luaotfload: необходимо для использования шрифтов OpenType в LuaTeX/LuaHBTeX

Механизм callback-функций LuaTeX для загрузки шрифтов обеспечивает большую гибкость, хотя и ценой дополнительного программирования. К счастью для пользователей LuaLaTeX, сообщество TeX разработало пакет под названием `luaotfload`luaotfload [ежегодного выпуска TeX Live](https://www.tug.org/texlive/) и, конечно, доступен пользователям Overleaf.

`luaotfload` равно [доступен на CTAN](https://ctan.org/pkg/luaotfload?lang=en) и имеет [репозиторий разработки на GitHub](https://github.com/latex3/luaotfload) где можно следить за последними изменениями и [новыми выпусками](https://github.com/latex3/luaotfload/releases).

`luaotfload` можно загрузить напрямую в преамбулу документа LaTeX через

```latex
\usepackage{luaotfload}
```

Обратите внимание, что `luaotfload` — это название LaTeX *пакет*, что означает, что у него имя файла `luaotfload.sty`. Если вы хотите использовать `luaotfload` с plain TeX, вы можете сделать это, добавив строку

```latex
\input luaotfload.sty
```

в ваш документ plain TeX.

Обычно пользователям LuaLaTeX — то есть тем, кто верстает LaTeX с использованием LuaTeX/LuaHBTeX, — не нужно напрямую взаимодействовать с `luaotfload` потому что [`fontspec` пакет](https://ctan.org/pkg/fontspec) загрузит `luaotfload` пакет для вас, беря на себя многие низкоуровневые детали через пользовательские команды, предоставляемые `fontspec` пакет.

### LuaHBTeX: новые варианты формирования текста

`luaotfload` — это зрелая и мощная библиотека Lua, которая обеспечивает работу LuaTeX со шрифтами OpenType — вместе с предоставлением услуг формирования текста для ряда языков и письменностей. Изначально функции формирования текста `luaotfload` были реализованы на чистом Lua, но выпуск TeX Live 2020 принёс ещё один основной вариант формирования текста — новый движок на базе LuaTeX под названием LuaHBTeX.

«HB» в LuaHBTeX означает HarfBuzz — по сути, LuaHBTeX представляет собой исходный движок LuaTeX *плюс* с интегрированным движком формирования текста HarfBuzz. В соответствии с философией проектирования LuaTeX наличие HarfBuzz не *автоматически* гарантирует, что текст будет сформирован LuaHBTeX: HarfBuzz — это ещё один инструмент, который можно использовать для создания решений по формированию текста.

Интеграция HarfBuzz в LuaHBTeX [программируется с помощью кода Lua](#introduction-to-the-luahbtex-harfbuzz-api), что позволило `luaotfload`разработчикам добавить решения формирования текста на основе HarfBuzz. В результате, [начиная с версии 3.1, выпущенной 5 ноября 2019 года](https://github.com/latex3/luaotfload/releases/tag/v3.1), `luaotfload` был улучшен, чтобы использовать HarfBuzz, сделав возможности формирования текста HarfBuzz легко доступными для обычного пользователя.

Читатели, интересующиеся техническими деталями интеграции HarfBuzz с LuaTeX, могут прочитать эту [статью Khaled Hosny](https://www.tug.org/TUGboat/tb40-1/tb124hosny-harfbuzz.pdf).

### luaotfload: два варианта формирования текста (когда использовать HarfBuzz?)

У пользователей LuaLaTeX теперь есть два варианта формирования текста:

* `luaotfload`исходная (узло-ориентированная) реализация формирования текста, написанная полностью на Lua;
* `luaotfload`формирование на основе HarfBuzz, к которому обращается код Lua, вызывающий функции формирования текста HarfBuzz.

`luaotfload` предоставляет доступ к этим двум системам формирования через свой параметр «`mode`», хотя большинство пользователей будет использовать эквивалентную `fontspec` “`Renderer`» опцию, а не напрямую использовать функции низкого уровня `luaotfload`.

Каждая из `luaotfload`решений для формирования текста имеет свои сильные стороны и (текущие) слабости, но какое из них следует использовать и когда? Вот несколько моментов, которые стоит учитывать:

* `luaotfload`родная узло-ориентированная обработка может потреблять много памяти, особенно для крупных шрифтов OpenType CJK. Использование HarfBuzz для формирования текста CJK может дать выигрыш в скорости и снизить потребление памяти.
* Используйте HarfBuzz для сложных письменностей, потому что он «...значительно улучшает отображение индийских и арабских письменностей и настоятельно рекомендуется для таких письменностей». (см. `luaotfload` руководство).
* Интеграция HarfBuzz в `luaotfload` всё ещё относительно нова и продолжает развиваться. На момент написания (июль 2021) рекомендуется использовать встроенное формирование luaotfload (устанавливая `mode=node`) для основных шрифтов документа, особенно если ваш документ использует латиницу. См. эту [проблему на GitHub](https://github.com/latex3/luaotfload/issues/175#issue-801120377), где суммируются проблемы и обсуждения. Если вы хотите поэкспериментировать, вы можете использовать `luaotfload` для загрузки файла шрифта и создания двух шрифтов LaTeX: один использует формирование на основе HarfBuzz, а другой — на основе Lua. Overleaf создал [пример проекта](#sample-project-arabic-shaping), который это демонстрирует.
* Не используйте HarfBuzz для работы с математическими шрифтами. Как обсуждалось разработчиками на tex.stackexchange, HarfBuzz [не предназначен для работы со шрифтами для математической верстки](https://tex.stackexchange.com/questions/544881/does-luahbtex-with-harfbuzz-renderer-completely-supports-math-formating) поэтому не используйте его для этой цели.

**Пример проекта: формирование арабского текста**

Вот проект Overleaf, который использует несколько высококачественных арабских гарнитур, чтобы сравнить `luaotfload`узло-ориентированные службы формирования текста `mode=node`с таковыми у HarfBuzz (`mode=harf`):

* <https://www.overleaf.com/latex/examples/complex-script-shaping-using-luaotfload-and-harfbuzz/gfssprnhfddn>

Этот проект включает результат, показанный на следующем изображении:

![Набор арабского текста](/files/b9e2f7e95145e694d633061f65c9537faa155406)

### Выбор «Renderer» в fontspec

Как отмечено в его [документацию](https://mirror.ox.ac.uk/sites/ctan.org/macros/unicodetex/latex/fontspec/fontspec.pdf), `fontspec` «...позволяет пользователям XeTeX или LuaTeX загружать шрифты OpenType в документ LaTeX». Если вы используете движки LuaTeX или LuaHBTeX, `fontspec` загрузит `luaotfload` библиотеку для вас и, кроме того, предоставят набор удобных пользовательских команд, которые избавляют от необходимости работать с `luaotfload`низкоуровневой функциональностью

Так как же выбрать между формированием HarfBuzz и встроенным формированием, предоставляемым `luaotfload`? Ответ содержится в превосходном [`fontspec` документацию](https://mirror.ox.ac.uk/sites/ctan.org/macros/unicodetex/latex/fontspec/fontspec.pdf), а именно в Части VI: функции шрифтов только для LuaTeX. `fontspec` предоставляет параметр под названием `Renderer` который можно задать при определении шрифта через `fontspec`. `Renderer` управляет низкоуровневой обработкой шрифта. Два интересующих нас варианта — это

* `Renderer = Node`: режим по умолчанию для набора шрифтов OpenType — он использует `luaotfload`функции формирования текста, реализованные полностью на Lua.
* `Renderer = Harfbuzz`: этот «режим» определяет/загружает шрифт для использования с движком формирования текста HarfBuzz. `luaotfload` использует API LuaHBTeX для вызова функций HarfBuzz.

Для получения дополнительной информации см. [`fontspec` документацию](https://mirror.ox.ac.uk/sites/ctan.org/macros/unicodetex/latex/fontspec/fontspec.pdf).

## Движки TeX, HarfBuzz и цветные эмодзи

Хотя XeTeX и LuaHBTeX оба интегрируют HarfBuzz, они обеспечивают разный уровень поддержки некоторых более продвинутых функций HarfBuzz — в частности, загрузки и использования цветных шрифтов OpenType.

### XeTeX и OpenType-цветные шрифты

Как отмечалось, существует две категории OpenType-цветных шрифтов в зависимости от формата данных, используемого для хранения глифов шрифта: векторные и растровые.

#### XeTeX и растровые OpenType-цветные шрифты

XeTeX не может загружать растровые OpenType-цветные шрифты — например, Google’s [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) поставляемый с TeX Live 2020. Например, если вы попытаетесь загрузить Noto Color Emoji (NotoColorEmoji.ttf), XeLaTeX завершится ошибкой с потенциально вводящим в заблуждение сообщением о том, что Noto Color Emoji «не удаётся найти». Следующий код LaTeX, набранный с помощью XeLaTeX, *не работает*:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emojifont{NotoColorEmoji.ttf}
\newcommand{\smiley}{{\emojifont\char"1F600}}
\smiley
\end{document}
```

[Откройте этот код XeLaTeX в Overleaf (он ***не*** работает).](https://www.overleaf.com/docs?engine=xelatex\&snip_name=XeTeX+failure\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%7BNotoColorEmoji.ttf%7D%0A%5Cnewcommand%7B%5Csmiley%7D%7B%7B%5Cemojifont%5Cchar%221F600%7D%7D%0A%5Csmiley%0A%5Cend%7Bdocument%7D)

Он завершается с ошибкой:

```
! Ошибка пакета fontspec: шрифт "NotoColorEmoji" не найден.
```

Аналогично, простой пример Plain TeX, обработанный XeTeX, тоже завершается ошибкой

```latex
\font\emojifont="[NotoColorEmoji.ttf]" at 12pt
\emojifont \char"1F600
\bye
```

[Откройте этот пример Plain TeX (XeTeX) в Overleaf (он ***не*** работает).](https://www.overleaf.com/docs?engine=latex_dvipdf\&snip_name\[]=main.tex\&snip\[]=%25%5Ctitle%7Bdummy+title%7D%0A%5Cfont%5Cemojifont%3D%22%5BNotoColorEmoji.ttf%5D%22+at+12pt%0A%5Cemojifont+%5Cchar%221F600%0A%5Cbye\&snip_name\[]=readme\&snip\[]=This+project+uses+a+latexmkrc+file+to+run+xetex+not+xelatex\&snip_name\[]=latexmkrc\&snip\[]=%24latex+%3D+%27xetex%25O+%25S%27%3B+%23+to+use+the+xetex+engine\&main_document=main.tex)

Пример Plain TeX сообщает похожее, но иное сообщение об ошибке:

```
! Шрифт \emojifont=[NotoColorEmoji.ttf] at 12.0pt не загружается: файл метрики (TFM)
или установленный шрифт не найден.
l.1 \font\emojifont="[NotoColorEmoji.ttf]" at 12pt

Мне не удалось прочитать данные о размере этого шрифта,
поэтому я проигнорирую спецификацию шрифта.
[Специалисты могут исправить файлы TFM с помощью TFtoPL/PLtoTF.]
Вы можете попробовать вставить другую спецификацию шрифта;
например, введите `I\font<тот же идентификатор шрифта>=<имя замещающего шрифта>'.
```

**Пример Plain LuaHBTeX**

Для сравнения, вот минимальный пример Plain TeX, скомпилированный с LuaHBTeX

```latex
\input luaotfload.sty
\font\emojifont=NotoColorEmoji.ttf:mode=harf at 12pt
\emojifont \Uchar"1F600
\bye
```

[Откройте этот пример Plain TeX (LuaHBTeX) в Overleaf (он успешно компилируется).](https://www.overleaf.com/docs?engine=latex_dvipdf\&snip_name\[]=main.tex\&snip\[]=%25%5Ctitle%7BPlain+TeX+with+LuaHBTeX%7D%0A%5Cinput+luaotfload.sty%0A%5Cfont%5Cemojifont%3DNotoColorEmoji.ttf%3Amode%3Dharf+at+12pt%0A%5Cemojifont+%5CUchar%221F600%0A%5Cbye\&snip_name\[]=readme\&snip\[]=This+project+uses+a+latexmkrc+file+to+run+luahbtex+not+lualatex\&snip_name\[]=latexmkrc\&snip\[]=%24latex+%3D+%27luahbtex+%25O+%25S%27%3B+%23+to+use+the+luahbtex+engine\&main_document=main.tex)

#### Истинная причина сбоя XeTeX

Сообщения об ошибках, выдаваемые XeTeX, частично скрывают истинную причину проблемы: OpenType-цветные шрифты, особенно растровые варианты,  *не* поддерживаются XeTeX. На самом деле XeTeX (Kpathsea) может *находить* шрифт Noto Color Emoji, но XeTeX не может полностью *загрузить* этот шрифт и не может инициализировать внутренние таблицы данных шрифта, необходимые для набора с его помощью. Внутри XeTeX *начинает* процесс загрузки шрифта и проверяет его на «масштабируемость» (используя определение «масштабируемости» FreeType), но эта проверка не проходит, и XeTeX выдаёт стандартное, и, возможно, вводящее в заблуждение сообщение об ошибке движка TeX.

**Техническое примечание**

Обработка NotoColorEmoji.ttf в XeTeX была исследована путём компиляции отладочной версии исполняемого файла XeTeX. В IDE Eclipse был установлен breakpoint на функцию XeTeX `creatFontFromFile(filename, index, pointsize)`, а затем пошагово пройти по коду, чтобы наблюдать последующую обработку.

#### XeTeX и векторные OpenType-цветные шрифты

XeTeX может *загрузить* использовать векторные OpenType-цветные шрифты, но не будет создавать цветные эмодзи в результирующем PDF — если XeTeX вообще создаст его. В отличие от LuaTeX, LuaHBTeX и pdfTeX, XeTeX не *непосредственно* выводит набранные документы в формате PDF. Вместо этого XeTeX выводит промежуточный `.xdv` (рас**x**ширенный **dvi**) файловый формат, который преобразуется в PDF с помощью утилиты под названием `xdvipdfmx`. На момент написания, `xdvipdfmx` не может встроить в PDF соответствующие данные цветных глифов эмодзи, поэтому, в лучшем случае, в PDF вы увидите монохромные эмодзи — «результат-замену» — или, возможно, вообще ничего, в зависимости от используемого шрифта.

Вот пример XeLaTeX, который использует OpenType-цветной шрифт [TwemojiMozilla.ttf](https://ctan.org/tex-archive/fonts/twemoji-colr), доступный в TeX Live. TwemojiMozilla.ttf использует векторный формат Microsoft COLR/CPAL для хранения цветных глифов и поставляется с TeX Live 2020. В этом примере XeTeX способен загрузить шрифт, создать `.xdv` и PDF-файл, но глиф эмодзи отсутствует в набранном PDF:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emojifont{TwemojiMozilla.ttf}
\newcommand{\smiley}{{\emojifont\char"1F600}}
Вот смайлик: \smiley
\end{document}
```

[Откройте этот код XeLaTeX в Overleaf (он НЕ РАБОТАЕТ).](https://www.overleaf.com/docs?engine=xelatex\&snip_name=XeTeX+failure\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%7BTwemojiMozilla.ttf%7D%0A%5Cnewcommand%7B%5Csmiley%7D%7B%7B%5Cemojifont%5Cchar%221F600%7D%7D%0AHere+is+a+smiley%3A+%5Csmiley%0A%5Cend%7Bdocument%7D)

Напротив, приведённый выше код работает с LuaLaTeX, если определить `\emojifont` с использованием `fontspec` настройки `[Renderer=HarfBuzz]`:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emojifont{TwemojiMozilla.ttf}[Renderer=HarfBuzz]
\newcommand{\smiley}{{\emojifont\char"1F600}}
Вот смайлик: \smiley
\end{document}
```

[Откройте этот код LuaLaTeX в Overleaf (он работает).](https://www.overleaf.com/docs?engine=lualatex\&snip_name=LuaLaTeX+emoji+example\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%7BTwemojiMozilla.ttf%7D%5BRenderer%3DHarfBuzz%5D%0A%5Cnewcommand%7B%5Csmiley%7D%7B%7B%5Cemojifont%5Cchar%221F600%7D%7D%0AHere+is+a+smiley%3A+%5Csmiley%0A%5Cend%7Bdocument%7D)

### LuaHBTeX и OpenType-цветные шрифты

Благодаря встроенному механизму шейпинга HarfBuzz и библиотеке `luaoftload` LuaHBTeX поддерживает все четыре разновидности OpenType-цветных шрифтов. Пользователи LuaLaTeX могут в полной мере воспользоваться обработкой Unicode текста, содержащего символы эмодзи, или просто украсить свои документы очень красочным текстом с помощью OpenType-цветных шрифтов.

Как отмечалось ранее, четыре варианта OpenType-цветных шрифтов можно разделить на две группы:

* те, что содержат глифы в растровых форматах изображений, таких как PNG;
* другие, использующие векторные форматы SVG или механизм Microsoft COLR/CPAL.

Векторные форматы глифов обладают преимуществом масштабируемости: они обеспечивают чёткую графику глифов при любом размере шрифта.

**Использование цветных шрифтов Microsoft COLR/CPAL в LuaHBTeX**

Если вы хотите использовать векторный формат для своих OpenType-цветных шрифтов эмодзи, обратите внимание на шрифт [TwemojiMozilla.ttf](https://ctan.org/tex-archive/fonts/twemoji-colr?lang=en)TwemojiMozilla.ttf, который основан на формате Microsoft COLR/CPAL. TwemojiMozilla.ttf включён в TeX Live, но вы можете получить последнюю версию с его [Репозиторий GitHub](https://github.com/mozilla/twemoji-colr/releases) и загрузить её в ваш проект Overleaf.

Вот небольшой, `fontspec`-основанный пример с использованием `Renderer=HarfBuzz`, который набирает большую (векторную) утку-эмодзи:

```latex
\documentclass{article}
\usepackage{fontspec}
\title{Duck demo}
\begin{document}
\newfontfamily\emojifont[Renderer=HarfBuzz,SizeFeatures={Size=400}]{TwemojiMozilla.ttf}
\emojifont\Uchar"1F986
\end{document}
```

[Откройте этот пример LuaLaTeX, чтобы набрать векторную утку.](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Typesetting+an+emoji+duck\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Ctitle%7BDuck+demo%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%5BRenderer%3DHarfbuzz%2CSizeFeatures%3D%7BSize%3D400%7D%5D%7BTwemojiMozilla.ttf%7D%0A%5Cemojifont%5CUchar%221F986%0A%5Cend%7Bdocument%7D)

Вот (векторная) утка, полученная в приведённом выше примере:

![](/files/76ac1584ef4fc5f2f3dc086eae095530b11015da)

#### Использование цветных шрифтов OpenType на основе SVG с LuaHBTeX

На момент написания этой обновлённой версии статьи (июль 2023) существует мало формальной документации по использованию OpenType-цветных шрифтов SVG-формата с LuaLaTeX. Некоторые [комментарии, сделанные в онлайн-обсуждениях,](https://github.com/latex3/luaotfload/issues/96) рекомендуют использовать `fontspec`его `RawFeature`, как показано в псевдокоде ниже. Замените `*имя вашего SVG-файла шрифта здесь*` на имя SVG-основанного файла шрифта, доступного вашему коду LaTeX:

```latex
\documentclass{article}
\usepackage{fontspec}
\begin{document}
\newfontfamily\emoji[RawFeature={+svg},SizeFeatures={Size=20}]{your SVG font file name here}
\emoji Your emoji here...
\end{document}
```

Если вы опустите `fontspec` и загрузите `luaotfload` напрямую, вам может потребоваться объявить и указать шрифт следующим образом — наши эксперименты показывают, что вам нужно опустить `mode=harf` этот параметр, чтобы это сработало:

```latex
\font\emoji=[your SVG font file name here]:+svg;
```

**Несколько предостережений**

Читателям, желающим использовать OpenType-цветные шрифты SVG-формата, следует учесть:

* OpenType-шрифты SVG-формата, содержащие большое количество глифов, могут быть [вычислительно затратными для LuaLaTeX](#processing-svg-glyph-data) при обработке, что потенциально приводит к [тайм-аутам Overleaf](/latex/ru/baza-znanii/038-fixing-and-preventing-compile-timeouts.md).
* Поддержка этих шрифтов в LuaLaTeX может [рассматриваться как экспериментальная](https://github.com/latex3/luaotfload/issues/96#issuecomment-530317399): результаты могут различаться в зависимости от выпуска TeX Live, используемого вашим проектом; поэтому рекомендуется экспериментировать и действовать осторожно.

**Обработка данных SVG-глифов**

SVG позволяет дизайнерам создавать сложные и красочные изображения, представляющие глифы шрифта, — с учётом некоторых ограничений SVG [документированных в спецификации OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/svg). Однако движки TeX, включая LuaHBTeX, не могут напрямую импортировать (использовать) SVG-файлы или данные — например, SVG-данные, используемые для описания форм глифов внутри OpenType-цветных шрифтов SVG-формата. SVG-данные глифа должны быть преобразованы в формат PDF, потому что LuaHBTeX может использовать его для набора глифа и создания итогового PDF-документа. Это преобразование SVG в PDF выполняется Lua-кодом внутри `luaoftload`: SVG-данные каждого глифа извлекаются из файла шрифта, сохраняются во временный `.svg` файл и преобразуются в PDF с помощью Inkscape через командную строку. Извлечение SVG-данных и их преобразование в PDF создают некоторую вычислительную нагрузку, что может привести к длительному времени компиляции документа — особенно в документах, использующих большие SVG-шрифты, содержащие тысячи глифов эмодзи.

#### Растровые OpenType-цветные шрифты

**Использование формата OpenType-цветных шрифтов Google CBDT/CBLC в LuaHBTeX**

[Noto Color Emoji](https://fonts.google.com/noto/specimen/Noto+Color+Emoji) — это OpenType-цветной шрифт, входящий в состав TeX Live, поэтому его легко использовать в проекте Overleaf. Поскольку Noto Color Emoji использует графику в формате PNG для представления глифов эмодзи, мы можем использовать его для набора крупного (растрового) эмодзи-утки — как показано в следующем примере. Ещё раз обратите внимание, что `fontspec` объявление шрифта (`\emojifont`) использует `Renderer=HarfBuzz`.

```latex
\documentclass{article}
\usepackage{fontspec}
\title{Duck demo}
\begin{document}
\newfontfamily\emojifont[Renderer=HarfBuzz,SizeFeatures={Size=400}]{NotoColorEmoji.ttf}
\emojifont\Uchar"1F986
\end{document}
```

[Откройте этот пример LuaLaTeX, чтобы набрать растровую утку.](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Typesetting+a+large+raster+duck\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bfontspec%7D%0A%5Ctitle%7BDuck+demo%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewfontfamily%5Cemojifont%5BRenderer%3DHarfbuzz%2CSizeFeatures%3D%7BSize%3D400%7D%5D%7BNotoColorEmoji.ttf%7D%0A%5Cemojifont%5CUchar%221F986%0A%5Cend%7Bdocument%7D)

Вот растровая утка, полученная в приведённом выше примере:

![Растровая утка-эмодзи, набранная LaTeX](/files/f87a701185bd957011021dc58ff3d644555880d5)

Если вы попытаетесь использовать `NotoColorEmoji.ttf` но опустите `[Renderer=HarfBuzz]` из `fontspec` объявления, LuaHBTeX завершится ошибкой и выдаст сообщение об ошибке, когда попытается записать PDF-файл:

```latex
! error:  (file /usr/local/texlive/2020/texmf-dist/fonts/truetype/google/noto-em
oji/NotoColorEmoji.ttf) (ttf): loca table not found
```

Причина этой ошибки в [таблице loca](https://docs.microsoft.com/en-us/typography/opentype/spec/loca) равно [объясняется на GitHub](https://github.com/latex3/luaotfload/issues/98#issuecomment-531610153).

**Использование формата OpenType-цветных шрифтов Apple sbix в LuaHBTeX**

Офлайн-тесты показывают, что LuaHBTeX поддерживает `sbix` вариант OpenType-цветных шрифтов, но на момент написания этой статьи нам не удалось найти надлежащим образом лицензированный `sbix`-вариант цветного шрифта эмодзи, чтобы продемонстрировать набор утки. Пожалуйста, [свяжитесь с нами](https://www.overleaf.com/contact) если вы знаете такой шрифт, сообщите нам, и мы быстро («quackly») обновим статью, чтобы использовать его.

## Введение в API HarfBuzz в LuaHBTeX

![Db.gif](/files/f6ce6bab6ac321fea22890320c9da39c22307149) ![Db.gif](/files/f6ce6bab6ac321fea22890320c9da39c22307149)

Формирование текста, особенно для языков со сложными письменностями, и даже эмодзи, — изначально сложная задача, поэтому неудивительно, что HarfBuzz — это сложная библиотека, с которой бывает непросто работать, если только вы уже не знакомы с операциями формирования текста. В этом заключительном разделе мы рассмотрим интеграцию HarfBuzz в LuaHBTeX и то, как получить к ней доступ через Lua-код внутри `\directlua`.

Наш пример использует довольно простой код, чтобы продемонстрировать API HarfBuzz LuaHBTeX. Он несколько искусственен, не соответствует уровню производственного качества и не очень практичен, потому что его единственная цель — представить некоторые ключевые идеи. Мы разделили Lua-код на две `\directlua` части: первая загружает `luaharfbuzz` библиотеку и создаёт некоторые глобальные переменные, которые мы будем использовать во второй `\directlua` части, где мы определяем макрос под названием `\codestoemoji`.

Кажется уместным воспроизвести использование Кнутом двойных знаков «опасный поворот» (изображение любезно предоставлено [этим сайтом](http://www.truetex.com/db.htm)) потому что содержание несколько низкоуровневое и «заглядывает под капот» — хотя мы надеемся, что оно может быть интересно более смелому читателю. Интеграция HarfBuzz в LuaHBTeX основана на [проекте luaharfbuzz на GitHub](https://github.com/ufyTeX/luaharfbuzz/wiki#projects-using-luaharfbuzz) где вы можете найти [введение в проект](https://github.com/ufyTeX/luaharfbuzz/wiki) вместе с [списком API luaharfbuzz](http://ufytex.github.io/luaharfbuzz/).

### Первые шаги: загрузите библиотеку luaharfbuzz и найдите шрифт

Чтобы использовать API HarfBuzz в LuaHBTeX, сначала нужно загрузить библиотеку (модуль) под названием `luaharfbuzz`, встроенную в LuaHBTeX, и сохранить возвращаемую таблицу в (глобальной) переменной, которую мы назовём `hblib`:

```latex
hblib=require("luaharfbuzz")
```

Затем нам нужно найти подходящий OpenType-цветной шрифт эмодзи: мы используем Noto Color Emoji — заметьте, мы очень ленимся и не делаем никакой проверки ошибок на случай, если не найдём его! Чтобы найти его, мы воспользуемся `библиотекой` (Kpathsea), которая также является частью LuaTeX/LuaHBTeX:

```latex
pathtofontfile=kpse.find_file("NotoColorEmoji.ttf","truetype fonts")
```

Теперь, когда у нас есть доступ к библиотеке HarfBuzz через нашу переменную `hblib`, а также путь к подходящему шрифту (`pathtofontfile`), мы можем начать использовать `hblib`. Для начала мы создадим объект шрифта HarfBuzz и объект face HarfBuzz для использования во второй `\directlua` части кода, где мы определяем наш макрос.

```latex
%Создайте HarfBuzz face и шрифт HarfBuzz из Noto Color Emoji
hbface = hblib.Face.new(pathtofontfile)
hbfont = hblib.Font.new(hbface)
```

#### Шрифт HarfBuzz и объект face HarfBuzz: что это такое?

Один [Объект HarfBuzz face](https://harfbuzz.github.io/fonts-and-faces.html) представляет гарнитуру, загруженную из файла шрифта, но без установки конкретных параметров (таких как размер). [Объект шрифта HarfBuzz](https://harfbuzz.github.io/fonts-and-faces.html) представляет *конкретный экземпляр* объекта HarfBuzz face; соответственно, из одного объекта HarfBuzz face можно вывести разные объекты шрифта HarfBuzz: у каждого шрифта HarfBuzz его свойства, такие как размер, могут иметь разные значения. Объект HarfBuzz face является более высоким уровнем абстракции, чем шрифт HarfBuzz.

### Использование глифов шрифта для создания PNG-файлов

Заключительная часть нашей первой `\directlua` части — это функция под названием `writePNGglyph(hbfontobject, glyphID)` которую мы используем, чтобы показать, что некоторые OpenType-цветные шрифты, такие как Noto Color Emoji, используют графику PNG для представления содержащихся в них глифов эмодзи.

Эта функция использует API HarfBuzz в LuaHBTeX, чтобы извлекать PNG-данные из глифов и записывать эти данные в `.png` файл под названием `Graphics<glyphID>.png`. Имя этого `.png` файла возвращается для использования `\includegraphics` для встраивания PNG-изображений глифов в наш набранный PDF.

С `writePNGglyph(hbfontobject, glyphID)` на месте, наша первая `\directlua` часть кода выглядит так:

```latex
\directlua{

% Загрузите библиотеку luaharfbuzz из LuaHBTeX
hblib=require("luaharfbuzz")

% Найдите шрифт Noto Color Emoji на сервере Overleaf
pathtofontfile=kpse.find_file("NotoColorEmoji.ttf","truetype fonts")

% Создайте HarfBuzz face и шрифт HarfBuzz из Noto Color Emoji
hbface = hblib.Face.new(pathtofontfile)
hbfont = hblib.Font.new(hbface)

% Эта функция принимает шрифт и идентификатор глифа:
% она извлекает PNG-данные глифов и записывает
% их в файл .png

function writePNGglyph(hbfontobject, glyphID)

    % Получить PNG-данные глифа
    local pngblob=hbfontobject:ot_color_glyph_get_png(glyphID)
    local pngdata=pngblob:get_data()

    % Сформировать имя файла для нашего файла .png
    local fname="Glyph"..glyphID..".png"

    % Записать файл .png и вернуть имя файла
    local output = assert(io.open(fname, "wb"))
    output:write(pngdata)
    output:close()

    % Вернуть имя файла для использования \includegraphics
    return fname
end
}
```

### Вторая часть \directlua: создать макрос \codestoemoji

Цель — определить макрос `\codestoemoji` который мы можем вызывать с фрагментом текста, содержащим коды символов эмодзи, которые мы хотим сформировать с помощью HarfBuzz. В частности, мы будем использовать `\Uchar<код символа>` для представления каждого символа эмодзи; например:

```latex
\codestoemoji{\Uchar"1F3F4\Uchar"E0067\Uchar"E0062\Uchar"E0065\Uchar"E006E\Uchar"E0067\Uchar"E007F}
```

Многое происходит внутри определения `\codestoemoji` которое мы объясним ниже, но определение выглядит так:

```latex
\newcommand{\codestoemoji}[1]{%
\directlua{

local str="#1"
local hbbuffer = hblib.Buffer.new()
hbbuffer:add_utf8(str)

hbbuffer:set_direction(hblib.Direction.new("ltr"))
local res = hblib.shape_full(hbfont, hbbuffer, {},{})

if (res) then
    local hbglyphs=hbbuffer:get_glyphs()
    % Таблица глифов, hbglyphs, имеет индексацию с 1
    local i = 1
    while hbglyphs[i] \noexpand~= nil do
        local glyph = hbglyphs[i]
        i = i + 1
        local fname=writePNGglyph(hbfont, glyph.codepoint)
        % Уменьшить размер импортированных PNG-изображений
        local s = 0.75
        local scal="[scale="..tostring(s).."]"
        tex.print([[\noexpand\includegraphics]]..scal..[[{]]..fname..[[}]])
     end
end
}}
```

#### Понимание определения макроса \codestoemoji

Это `\codestoemoji` макрос в основном представляет собой Lua-код, содержащийся внутри `\directlua`, поэтому если вы хотите узнать больше о том, как *как* `\directlua` это работает, ознакомьтесь со статьёй Overleaf [Понимание `\directlua`](/latex/ru/podrobnye-stati/09-an-introduction-to-luatex-part-2-understanding-directlua.md). В ней объясняется, как LuaTeX и LuaHBTeX обрабатывают `\directlua` когда в Lua-код включены команды TeX/LaTeX, и, в частности, необходимость использовать `\noexpand` и `\unexpanded`.

**Работа с параметром макроса: "#1"**

Макрос начинается с этих трёх строк:

```latex
local str="#1"
local hbbuffer = hblib.Buffer.new()
hbbuffer:add_utf8(str)
```

которые выполняют следующие задачи:

* `local str="#1"`: это создаёт Lua-строку из ввода, переданного макросом;
* `local hbbuffer = hblib.Buffer.new()`: это использует API HarfBuzz для создания буфера, в котором будет храниться текст, который мы хотим сформировать с помощью HarfBuzz;
* `hbbuffer:add_utf8(str)`: это добавляет строку в формате UTF-8, созданную из ввода нашего макроса, в буфер HarfBuzz.

Первая строка кода

```latex
local str="#1"
```

кажется довольно простой, но её работа включает немалую сложность, которую стоит рассмотреть подробнее.

Если мы рассмотрим третью строку кода

```latex
hbbuffer:add_utf8(str)
```

мы увидим, что она использует нашу `str` переменную, чтобы предоставить буферу HarfBuzz строку Unicode, отформатированную в UTF-8. Чтобы это работало, переменная `str` сама должна содержать текст Unicode, отформатированный в UTF-8; поэтому возникает вопрос: *как* преобразовал ли LuaHBTeX аргумент макроса `"#1"`, содержащий `\Uchar` команды, в Lua-строку `str` содержащую UTF-8-текст для HarfBuzz?

Если мы посмотрим на предполагаемое использование `\codestoemoji` макроса:

```latex
\codestoemoji{\Uchar"1F3F4\Uchar"E0067\Uchar"E0062\Uchar"E0065\Uchar"E006E\Uchar"E0067\Uchar"E007F}
```

входные данные, такие как `\Uchar"1F3F4\Uchar"E0067\Uchar"E0062\Uchar"E0065...`, совсем не похожи на последовательность символов эмодзи, закодированных в UTF-8. Более того, HarfBuzz ничего не знает о командах TeX. Тем не менее, необработанный ввод TeX, состоящий из `\Uchar` команд, преобразуется в символы Unicode, закодированные в UTF-8, которые HarfBuzz может использовать, но *как*?

Ответ кроется в поведении `\Uchar` команды: попытка вызвать `\codestoemoji` с помощью `\char` вместо `\Uchar` завершится неудачей, но *почему*?

**Расширение \Uchar в \directlua**

Когда `\codestoemoji` макрос вызывается, `\directlua` команда, хранящаяся в определении макроса, должна подготовить Lua-код для отправки во встроенный интерпретатор Lua в LuaHBTeX. Часть этого процесса подготовки кода заключается в раскрытии любых команд TeX/LaTeX, присутствующих в исходном Lua-коде в определении макроса, а также в раскрытии любых аргументов макроса, предоставленных пользователем. Этот процесс раскрытия даёт список токенов, который затем преобразуется обратно в текст, формируя Lua-код для передачи интерпретатору Lua. Для удобства мы воспроизводим диаграмму из статьи Overleaf [Понимание `\directlua`](/latex/ru/podrobnye-stati/09-an-introduction-to-luatex-part-2-understanding-directlua.md):

![Механика \directlua](/files/7117d7abe64daca65226c32c90b19c6ede63eb7b)

Макрос `\codestoemoji` предназначен для вызова с помощью `\Uchar` команд, и, [как отмечалось ранее в статье](#the-key-difference-expansion), `\Uchar` является расширяемой командой, чьё расширение генерирует символьный токен. В ходе обработки `\directlua`LuaHBTeX раскрывает каждую `\Uchar<код символа>` команду, где она *удаляет* каждый `\Uchar<код символа>` извлекается из ввода и *заменяет* её соответствующим значением раскрытия: символьным токеном, представляющим `<код символа>`.

На заключительном этапе обработки исходный список токенов, сгенерированный `\directlua` преобразуется *обратно в текст* чтобы стать кодом Lua, предназначенным для интерпретатора Lua (см. диаграмму выше). Все символьные токены, полученные в результате развёртывания `\Uchar` также *преобразуются обратно в текст*: это преобразование символьных токенов в текст генерирует UTF-8-представления исходных `<код символа>` значений.

В нашем примере к тому времени, как код Lua сгенерирован и готов для интерпретатора Lua, вход макроса для "#1" был преобразован в последовательность UTF-8-текста: `str` переменная теперь является строкой UTF-8, которую можно безопасно добавить в буфер HarfBuzz.

**Почему не работает \char?**

Краткий ответ: потому что `\char` равно *не* это расширяемая команда. В отличие от `\Uchar` команд, `\char` команды *не удаляются* из ввода во время `\directlua`первоначальной обработки для генерации списка токенов, они «проходят сквозь» и включаются в список токенов, который формируется `\directlua`. Например, если аргумент `\codestoemoji` содержал `\char"1F3F4` LuaHBTeX преобразовал бы это в последовательность токенов и сохранил бы их как часть общего списка токенов, который генерируется.

На следующем этапе обработки, при преобразовании токенов обратно в текст, получившийся код Lua будет содержать *буквальную строку* `\char"1F3F4` в тексте, используемом для определения нашей переменной `str`. Когда содержимое `str` добавляется в буфер HarfBuzz, оно не будет содержать UTF-8-кодированную последовательность, представляющую символ эмодзи "1F3F4; вместо этого оно будет содержать буквальную строку `\char"1F3F4`, которую HarfBuzz попытается сформировать и, в нашем случае, не даст глиф эмодзи. Кстати, строка `\char"1F3F4` также вызывала бы синтаксические ошибки Lua, если бы не была создана как «длинная строка в квадратных скобках» — см. [Что такое escape-последовательности Lua](/latex/ru/podrobnye-stati/09-an-introduction-to-luatex-part-2-understanding-directlua.md#what-are-e2809clua-escape-sequencese2809d3f) для справки по этому вопросу.

Если мы попытаемся использовать `\codestoemoji` с `\char` команду, вот так:

```latex
\codestoemoji{\char"1F3F4\Uchar"E0067\Uchar"E0062\Uchar"E0065\Uchar"E006E\Uchar"E0067\Uchar"E007F}
```

LuaHBTeX завершится с ошибкой и сообщит о синтаксической ошибке примерно такой:

```latex
[\directlua]:1: invalid escape sequence near '"\c'.
\codestoemoji ...ing \includegraphics }.}]]) end }

l.75 ...r"E0065\Uchar"E006E\Uchar"E0067\Uchar"E007F}

интерпретатор Lua столкнулся с проблемой, поэтому
остаток этого фрагмента Lua будет проигнорирован.
```

#### Вызов функции формирования HarfBuzz

**Задание параметров буфера**

HarfBuzz иногда требует дополнительную информацию о тексте, который ему предлагается сформировать. Вы можете предоставить эту информацию, настроив свой `<buffer variable>` с помощью *методы буфера*, например:

* `<buffer variable>:set_direction(*направление HarfBuzz*)`;
* `<buffer variable>:set_language(*язык HarfBuzz*)`;
* `<buffer variable>:set_script(*письмо HarfBuzz*)`.

Например, нам нужно сообщить HarfBuzz, что направление нашего текста с эмодзи будет слева направо. Для этого мы используем `set_direction()` метод в нашем `<buffer variable>` (называемом `hbbuffer`) написав:

```latex
hbbuffer:set_direction(hblib.Direction.new("ltr"))
```

где `hblib.Direction.new("ltr")` создаёт «объект направления», подходящий для передачи движку HarfBuzz через Lua.

**Выполнить формирование**

После того как буфер должным образом инициализирован, мы можем попросить HarfBuzz выполнить собственно формирование с помощью функции `shape_full()`. В нашем примере мы пишем:

```latex
local res = hblib.shape_full(hbfont, hbbuffer, {},{})
```

3-й и 4-й параметры `shape_full()` функции должны быть таблицами Lua — мы использовали пустые таблицы «`{}`» для обоих параметров. Общий вид `shape_full()` таков:

```latex
shape_full(шрифт Harfbuzz, буфер Harfbuzz, {свойства шрифта}, {"shaper"}
```

* **`{"shaper"}`**: Обычно не нужно задавать, но возможные варианты `{"ot"}` или `{"graphite2"}`. Дополнительную информацию о понятии «shaper» можно найти в [документации HarfBuzz](https://harfbuzz.github.io/shaping-and-shape-plans.html)—заметьте, здесь описан низкоуровневый C API, а не основанная на Lua `luaharfbuzz` обвязка (реализация).
* **`{свойства шрифта}`**: Это таблица, перечисляющая [функции OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist)—поддерживаемые шрифтом—которые вы хотите, чтобы HarfBuzz применил при формировании.

Любое свойство шрифта, которое вы хотите использовать, нужно создавать с помощью `luaharfbuzz` функции библиотеки

```latex
library_instance.Feature.new(feature_string)
```

где

* `library_instance` это ваша `luaharfbuzz` переменная экземпляра библиотеки (`hblib` в нашем примере);
* `feature_string` использует [синтаксис для определения свойств](https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings). Примерами этого являются `+smcp` для активации капители или `-kern` для отключения кернинга.

Например:

```latex
local dosmcp = hblib.Feature.new("+smcp")
local nokern = hblib.Feature.new("-kern")
% Используйте свойства шрифта так
local res = hblib.shape_full(hbfont, hbbuffer, {dosmcp,nokern},{})
```

#### Получение результата: извлечение глифов

И наконец, если операция формирования прошла успешно, сформированные глифы возвращаются в переменной буфера `hbbuffer` которую мы создали ранее в коде.

Мы получаем доступ к глифам через метод буфера `get_glyphs()` и используем цикл, чтобы получить каждый отдельный глиф. Обратите внимание, что таблица Lua, содержащая глифы, `hbglyphs` в нашем примере индексируется, начиная с 1, а не с 0.

У каждого глифа *идентификатор глифа* (что сбивает с толку, называется `codepoint`), и шрифт HarfBuzz (`hbfont`), передаются в `writePNGglyph()` функцию, которая создаёт PNG-файл, используя растровое представление этого глифа, полученное из шрифта.

`writePNGglyph()` записывает PNG-файл и возвращает имя PNG-файла, которое используется для импорта (масштабированного) PNG-файла в наш документ LaTeX с помощью `\includegraphics[scale=0.75]{<fname>}`. Обратите внимание, что мы можем использовать `\includegraphics` непосредственно внутри кода Lua.

```latex
if (res) then
    local hbglyphs=hbbuffer:get_glyphs()
    % Таблица глифов, hbglyphs, имеет индексацию с 1
    local i = 1
    while hbglyphs[i] \noexpand~= nil do
        local glyph = hbglyphs[i]
        i = i + 1
        local fname=writePNGglyph(hbfont, glyph.codepoint)
        % Уменьшить размер импортированных PNG-изображений
        local s = 0.75
        local scal="[scale="..tostring(s).."]"
        tex.print([[\noexpand\includegraphics]]..scal..[[{]]..fname..[[}]])
     end
end
```

### Полный код, который вы можете открыть в Overleaf

```latex
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\directlua{

% Загрузите библиотеку luaharfbuzz из LuaHBTeX
hblib=require("luaharfbuzz")

% Найдите шрифт Noto Color Emoji на сервере Overleaf
pathtofontfile=kpse.find_file("NotoColorEmoji.ttf","truetype fonts")

% Создайте HarfBuzz face и шрифт HarfBuzz из Noto Color Emoji
hbface = hblib.Face.new(pathtofontfile)
hbfont = hblib.Font.new(hbface)

% Эта функция принимает шрифт и идентификатор глифа:
% он извлекает PNG-данные глифа и записывает
% их в файл .png

function writePNGglyph(hbfontobject, glyphID)

    % Получить PNG-данные глифа
    local pngblob=hbfontobject:ot_color_glyph_get_png(glyphID)
    local pngdata=pngblob:get_data()

    % Сформировать имя файла для нашего файла .png
    local fname="Glyph"..glyphID..".png"

    % Записать файл .png и вернуть имя файла
    local output = assert(io.open(fname, "wb"))
    output:write(pngdata)
    output:close()

    % Вернуть имя файла для использования \includegraphics
    return fname
end
}

\newcommand{\codestoemoji}[1]{%
\directlua{

local str="#1"
local hbbuffer = hblib.Buffer.new()
hbbuffer:add_utf8(str)

hbbuffer:set_direction(hblib.Direction.new("ltr"))
local res = hblib.shape_full(hbfont, hbbuffer, {},{})

if (res) then
    local hbglyphs=hbbuffer:get_glyphs()
    % Таблица глифов, hbglyphs, индексируется с 1.
    local i = 1
    while hbglyphs[i] \noexpand~= nil do
        local glyph = hbglyphs[i]
        i = i + 1
        local fname=writePNGglyph(hbfont, glyph.codepoint)
        % Уменьшить размер импортированных PNG-изображений
        local s = 0.75
        local scal="[scale="..tostring(s).."]"
        tex.print([[\noexpand\includegraphics]]..scal..[[{]]..fname..[[}]])
     end
end
}}

Утка: \codestoemoji{\Uchar"1F986}

Флаг: \codestoemoji{\Uchar"1F3F4\Uchar"E0067\Uchar"E0062\Uchar"E0065\Uchar"E006E\Uchar"E0067\Uchar"E007F}
\end{document}
```

[Откройте этот пример API luaharfbuzz в Overleaf.](/latex/ru/podrobnye-stati/10-an-overview-of-technologies-supporting-the-use-of-colour-emoji-fonts-in-latex.md)

Этот пример выдаёт следующий результат:

![Harfbuzzexample.png](/files/9a3b581fff6115ae2ce57dbd34b20d62040a59dd)

## Бонусный раздел: забавная математика с эмодзи

В завершение, с лёгкой ноткой, один из участников команды Overleaf использовал [`эмодзи` пакет LaTeX](https://ctan.org/pkg/emoji?lang=en) чтобы создать забавный пример:

```latex
\documentclass{article}
\usepackage{emoji}
\usepackage{unicode-math,fontspec}
\setmainfont{STIX}
\setmathfont{STIX Two Math}
\begin{document}
\newcommand{\emomath}[1]{\text{\emoji{#1}}}
\[
e^{\emomath{droplet} \ln\emomath{smile}}=\emomath{sweat-smile}
\]
\[
e^{\emomath{eye}\emomath{pie}}=-1
\]
\end{document}
```

[Откройте этот забавный пример в Overleaf](https://www.overleaf.com/docs?engine=lualatex\&snip_name=Fun+with+emoji+math\&snip=%5Cdocumentclass%7Barticle%7D%0A%5Cusepackage%7Bemoji%7D%0A%5Cusepackage%7Bunicode-math%2Cfontspec%7D%0A%5Csetmainfont%7BSTIX%7D%0A%5Csetmathfont%7BSTIX+Two+Math%7D%0A%5Cbegin%7Bdocument%7D%0A%5Cnewcommand%7B%5Cemomath%7D%5B1%5D%7B%5Ctext%7B%5Cemoji%7B%231%7D%7D%7D%0A%5C%5B%0Ae%5E%7B%5Cemomath%7Bdroplet%7D+%5Cln%5Cemomath%7Bsmile%7D%7D%3D%5Cemomath%7Bsweat-smile%7D%0A%5C%5D%0A%5C%5B%0Ae%5E%7B%5Cemomath%7Beye%7D%5Cemomath%7Bpie%7D%7D%3D-1%0A%5C%5D%0A%5Cend%7Bdocument%7D)

Этот пример выдаёт следующий результат:

![Emojimath2.png](/files/977de91c3c58c00a925fc4aa397afa5bd6ae026b)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/ru/podrobnye-stati/10-an-overview-of-technologies-supporting-the-use-of-colour-emoji-fonts-in-latex.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
