Пользовательский шрифт дает неправильный символ для определенных комбинаций букв в Android

Я использую собственный шрифт в моем проекте Android. По какой-то причине, когда текст включает буквы IJ вместе, он дает мне следующий символ:

Введите описание изображения здесь

Кажется, это глиф, расположенный в \uE2C5 области PUA шрифта.

Индивидуальные I и J глифы существуют в шрифте, и я могу заставить их появиться, если я установил текст в IJ .

Введите описание изображения здесь

Это не шрифт OpenType (я не думаю, что Android даже поддерживает рендеринг OpenType в пользовательских шрифтах), поэтому не должно быть ничего подобного. Что здесь происходит?

Проблема воспроизводима с помощью следующего простого проекта:

 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = (TextView) findViewById(R.id.textview); Typeface tf = Typeface.createFromAsset(this.getAssets(), "MenksoftHawang.ttf"); textView.setTypeface(tf); textView.setText("IJ"); } } 

Шрифт можно скачать здесь . Поместите его в папку с ресурсами в проекте.

Solutions Collecting From Web of "Пользовательский шрифт дает неправильный символ для определенных комбинаций букв в Android"

Я не могу говорить о причине того, что вы видите то, что видите, но комбинация букв «IJ», похоже, имеет специальную форму. На странице Википедии о типографской лигатуре .

Голландский ij, однако, несколько более неоднозначен. В зависимости от используемого стандарта его можно считать орграфом, лигатурой или буквой в себе, а ее формы в верхнем и нижнем регистре часто доступны в виде одного символа с отличительной лигатурой в нескольких профессиональных шрифтах (например, Zapfino). Зашифрованные заглавные буквы Sans serif, популярные в Нидерландах, обычно используют лигатуру, напоминающую U со сломанным левым ударом.

Также из Википедии :

Подстановка и состав глифа

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

Лигатуры Лигатуры, такие как «ffi» в латинском алфавите, часто кодировались как отдельный символ в устаревших наборах символов. Подход Юникода к лигатурам относится к ним как к богатому тексту и, если он включен, обрабатывается путем замены символа.

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

Обновление Использование setFontFeatureSettings() позволяет отключить отображение глифа, как показано в следующем коде. К сожалению, это доступно только в API 21+. Существует предостережение, что могут быть другие побочные эффекты, о которых вы, возможно, узнаете.

Для API ниже 21 вы можете использовать программу редактирования шрифтов, такую ​​как FontForge, и удалить глиф в U + E2C5. Я сделал это, и он устраняет глиф. Это может быть лучший способ пойти до тех пор, пока вы думаете, что можете идентифицировать все комбинации букв, которые могут привести к глифу.

 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String features = "\"liga\"=0"; TextView textView = (TextView) findViewById(R.id.textview); Typeface tf = Typeface.createFromAsset(this.getAssets(), "MenksoftHawang" + ".ttf"); textView.setTypeface(tf); textView.setFontFeatureSettings(features); textView.setText("IJ ij"); } } 

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

Но в качестве обходного пути вы можете применить крошечное расстояние между буквами, которое будет отображать буквы, как ожидалось.

 textView1.setText("IJ"); textView2.setLetterSpacing(0.04f); textView2.setText("IJ"); 

Результат:

Введите описание изображения здесь

Кажется, есть три решения этой проблемы:

1. Программно отключить лигатуры

Вы можете отключить лигатуры программно с помощью setFontFeatureSettings (как предлагается здесь ) или setLetterSpacing (как предлагается здесь ). Одним из недостатков обоих этих методов является то, что они доступны только из API 21.

2. Отредактируйте лигатуры из шрифта

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

3. Используйте другой шрифт

В этом случае часто доступны разные шрифты, и это верно. У той же компании, у которой был проблематичный шрифт TrueType в вопросе, также есть версия этого шрифта OpenType. Версия OpenType, похоже, не имеет ошибок в лигатуре. Недостатком, однако, является то, что он значительно больше по размеру, что сделает размер загрузки приложения более крупным.

Заметки

  • Раньше я думал, что до Android 6.0 не было никакой лигатуры. Тем не менее, шрифты TrueType, по-видимому, поддерживают некоторые основные лигатуры, и они отображаются в версиях Android до 6.0.
  • Следующий образ из FontForge показывает все лигатуры, определенные в проблемном шрифте, на который ссылается вопрос. Введите описание изображения здесь