Все статьи
24 сентября 2026 г.8 мин чтения

Лигатура есть в проекте, но исчезла в файле шрифта: как проверить сборку GSUB

Лигатура есть в проекте, но исчезла в файле шрифта: как проверить сборку GSUB

Лигатура может быть нарисована и присутствовать в проекте, но при наборе сочетание букв всё равно останется раздельным. Причина часто не в контуре: правило подстановки не попало в собранную таблицу GSUB, ссылается на другое имя глифа или выключено при формировании строки. Ниже — способ пройти цепочку от исходника до сформированной последовательности глифов и определить, на каком этапе теряется функция.

Сначала разделите три разных объекта

В шрифте важно различать буквы-коды, глифы и правила их замены. Символы текста, например f и i, сопоставляются с базовыми глифами через cmap. Нарисованный глиф fi может существовать рядом с ними, но сам по себе он не говорит программе, когда его нужно показать. Для автоматической замены последовательности глифов используется GSUB — таблица подстановок OpenType. Microsoft описывает её как слой, который позволяет заменить несколько входных глифов одним, в том числе при формировании лигатуры.

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

Запишите ожидаемое поведение до пересборки

Начните с конкретной строки и режима. Для стандартной лигатуры fi обычно проверяют обычный текст с включённой функцией liga; декоративная или редкая замена может быть размечена как discretionary ligature и проверяться отдельно. Не смешивайте эти сценарии: стандартная и необязательная функции имеют разные теги, а приложение может включать их по-разному. Если функция нужна только для одного контекста, запишите и контекст — например, обычное сочетание, слово или границы пунктуации.

  1. Укажите входной текст в Unicode, например «fi» или «ffi».
  2. Запишите ожидаемый выходной глиф и имя, которое ему присвоено в проекте.
  3. Отметьте тег функции и включённое состояние; для проверки сравните включённый и выключенный режим.
  4. Используйте одну и ту же строку для исходника, теста компилятора и целевой программы.

Такой мини-тест предотвращает частую ошибку: автор ищет лигатуру по видимому слову, а на самом деле проверяет другую функцию или другую последовательность. Для рукописной гарнитуры заранее решите, является ли конкретное соединение автоматическим правилом или отдельным символом, который пользователь должен вставлять вручную.

Проверьте глиф и его имя в исходнике

Откройте именно исходный проект, из которого собирается финальный файл. Убедитесь, что глиф лигатуры не просто виден на странице, но сохранён как отдельный глиф с устойчивым именем. Затем сравните имена каждого компонента правила с именами реальных базовых глифов. В одном проекте визуально одинаковые глифы могут называться по-разному: например, `f`, `f.alt` и `f.locl`. Правило `sub f i by f_i;` не найдёт последовательность, если базовая буква на самом деле называется `f.alt` и правило не содержит соответствующего контекста.

Проверьте и состав лигатуры. Если цель — ffi, все три входных глифа должны присутствовать, а итоговый глиф должен быть тем, который использует правило. Для варианта fi внутри более длинной последовательности порядок и устройство lookup могут влиять на результат; не исправляйте такое поведение простым переименованием, пока не увидели фактически сформированную последовательность. Название глифа является меткой внутри проекта, а не заменой самому правилу.

Убедитесь, что правило включено в сборку

Редакторы шрифтов и конвейеры сборки хранят OpenType-функции по-разному: в панели функций, feature-коде, отдельном `.fea`-файле или конфигурации команды сборки. Найдите действительный входной файл текущей сборки и проследите его до команды экспорта. Если код лежит рядом с проектом, но сборщик его не читает, в превью редактора правило может работать, а в выгруженном TTF его не будет.

Для простого примера feature-код может описывать соответствие примерно так: `feature liga { sub f i by f_i; } liga;`. Это только иллюстрация структуры правила; синтаксис и место хранения зависят от редактора и компилятора. В FontTools библиотека feaLib читает и записывает OpenType feature-файлы, которые предназначены, среди прочего, для описания данных GSUB и GPOS. Поэтому при использовании `.fea` убедитесь, что файл добавлен в команду или конфигурацию сборки, а не только сохранён в каталоге.

Посмотрите журнал компилятора. Предупреждение о неизвестном имени глифа, дублирующемся определении, пустом lookup или пропущенном файле — полезная улика. Не игнорируйте сообщения лишь потому, что экспорт завершился успешно: сборщик может выдать валидный файл без правила, которое не смог обработать. Сохраните лог рядом с конкретной сборкой, чтобы сравнить его до и после правки.

Проверьте скомпилированный файл, а не только окно редактора

Сначала откройте экспортированный файл в редакторе таблиц шрифта или проверочном инструменте и убедитесь, что в GSUB есть нужный feature tag, lookup и входная пара глифов. Наличие записи `liga` само по себе недостаточно: она может содержать другой набор правил или отсылать к другой последовательности. Для контрольного теста сравните сборку с исходным файлом, когда редактор умеет открывать оба варианта.

Затем проверьте shaping. Утилита HarfBuzz `hb-shape` позволяет сформировать текст в последовательность позиционированных глифов и показать результат в терминале. Пример команды: `hb-shape ./MyFont.ttf "fi" --features=liga=1`. Запустите ту же команду с `--features=liga=0`. Если при включённой функции вывод меняется на имя глифа лигатуры, правило работает в этом файле и в этом shaping-сценарии. Если выход одинаков, вернитесь к GSUB, именам компонентов и настройке команды, а не к контуру.

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

Сравните включённый и выключенный режим в целевой программе

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

Если `hb-shape` показывает лигатуру, а целевая программа — нет, проверьте загрузку файла. Временно удалите или переименуйте ранее установленную копию, перезапустите приложение и подтвердите полное имя и версию открытого шрифта. Это отделяет проблему экспорта от кеша или случайно выбранной гарнитуры. Не делайте вывод по одному текстовому полю: некоторые приложения имеют собственный переключатель OpenType-функций или отключают их для отдельных режимов.

Как быстро определить этап сбоя

  1. Целевого глифа нет в исходнике — создайте его или исправьте мастер, затем пересоберите.
  2. Глиф есть, но rule отсутствует в исходном проекте — добавьте или включите feature и проверьте имена компонентов.
  3. Правило есть в проекте, но нет в GSUB — проверьте, какие файлы и опции реально поданы компилятору.
  4. В GSUB правило есть, но `hb-shape` не заменяет последовательность — проверьте tag, входные glyph IDs, условия и настройку теста.
  5. HarfBuzz заменяет глифы, а приложение нет — проверьте включение функции, фактически загруженный файл и кэш приложения.

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

Частые ошибки

  • Проверять только наличие глифа. Без связанного правила он не будет автоматически подставляться в обычном тексте.
  • Искать один тег, когда лигатура размечена другой функцией. Сначала уточните, стандартная это замена или декоративная.
  • Собирать старый файл проекта или копию feature-кода. Сверьте путь к исходнику и время создания результата.
  • Считать успешный экспорт доказательством успешного набора. Файл может быть технически валидным, хотя нужного lookup в нём нет.
  • Оценивать подстановку только по скриншоту. В тесте shaping сравните фактические имена сформированных глифов.
  • Удалять правило, если приложение его не показывает. Сначала отделите экспорт от настроек программы и её кеша.

Контрольный список перед передачей шрифта

Перед передачей сохраните чистую копию исходника, feature-код и журнал экспорта. В короткой карточке сборки зафиксируйте версию проекта, имя итогового файла, тег проверенной функции, контрольную строку и ожидаемые выходные глифы. Это не бюрократия: при следующей правке можно повторить тот же тест и понять, исчезло ли правило из-за изменения проекта, команды сборки или другого редактора.

  • Целевой глиф присутствует в том проекте, который действительно собран.
  • Правило ссылается на существующие имена компонентов и входит в сборочную конфигурацию.
  • Журнал компиляции не содержит необъяснённых предупреждений по feature-файлу.
  • В собранном файле есть нужная запись GSUB и соответствующий lookup.
  • Тест shaping с включённой функцией даёт замену, а с выключенной — исходную последовательность.
  • Целевое приложение показывает ту же версию шрифта после перезапуска.

Вопросы и ответы

Если глиф лигатуры есть в файле, зачем нужна GSUB?

Глиф — это форма, а GSUB — правило, которое указывает текстовому движку, когда заменить последовательность других глифов этой формой. В большинстве случаев обычный текст не содержит отдельного Unicode-символа «fi-лигатура», поэтому одной записи в cmap недостаточно.

Должна ли стандартная лигатура работать всегда?

Нет: результат зависит от того, включена ли соответствующая OpenType-функция и поддерживает ли её приложение в данном сценарии. Проверяйте свой целевой редактор и сравнивайте его с тестом shaping, где состояние функции задано явно.

Можно ли проверить GSUB без покупки редактора шрифтов?

Да. Инструменты семейства FontTools умеют инспектировать структуры OpenType, а HarfBuzz предоставляет `hb-shape` для просмотра результата формирования текста. Команду и способ просмотра подбирайте под установленную версию инструментов и храните вместе с заметкой о тесте.

Почему правило работает в редакторе проекта, но не после экспорта?

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

Если `hb-shape` показывает лигатуру, проблема решена?

Это подтверждает работу правила в конкретном файле и конфигурации HarfBuzz. Целевая программа может использовать другой движок, настройки функций или кешированный файл, поэтому контрольный набор всё равно нужно открыть в конечном приложении.

Нужно ли делать fi- и ffi-лигатуры для рукописного шрифта?

Это редакционное решение, а не обязательное требование формата. Добавляйте только те соединения, которые улучшают нужный почерк и не затрудняют распознавание слова; затем проверяйте короткие сочетания и реальные строки целевой аудитории.

Заключение

Диагностируйте лигатуру по цепочке: целевой глиф, исходное правило, конфигурация сборки, GSUB в финальном файле, затем shaping и целевое приложение. Так вы быстро отделите ошибку исходника от сбоя экспорта и от поведения программы. Если вы делаете собственный набор букв, начните с шаблона Fontgenerator, а после сборки проверяйте не только отдельные знаки, но и нужные сочетания в готовом шрифте.

Источники

Спецификация Microsoft OpenType: таблица GSUB и лигатурные подстановки — https://learn.microsoft.com/en-us/typography/opentype/spec/gsub

Документация FontTools feaLib — https://fonttools.readthedocs.io/en/stable/feaLib/index.html

Руководство HarfBuzz: утилита hb-shape — https://harfbuzz.github.io/harfbuzz-hb-shape.html

HarfBuzz: применение OpenType-функций — https://harfbuzz.github.io/shaping-opentype-features.html