Автор Тема: Кернинг  (Прочитано 2175 раз)

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Кернинг
« : 22 Январь 2016, 16:22:15 »
Уважаемый админ!
Появится ли в приложении кернинг? Дело в том, что в некоторых шрифтах при неработающем кернинге некорректно отображается текст (например, сочетание букв "гд", отображённое шрифтом Canonic, выглядит как "г д").  :'(
И ещё. Если не трудно, добавьте, пожалуйста, настройки цвета киновари и ссылок отдельно для дневного и ночного режимов.

P.S. Спасибо за отличное приложение.  :-*

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #1 : 25 Январь 2016, 13:19:07 »
Уточните, пожалуйста, что понимается под "появится кернинг"?

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

Отдельные настройки цветов, вероятно, появятся в будущей версии приложения.

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #2 : 25 Январь 2016, 22:03:19 »
Давайте для начала посмотрим скриншоты.
а) LibraryCS, текст как есть (первое вложение)
б) MSWord, текст с отключенным кернингом и с включенным кернингом (второе вложение).

На основании приведённых скринов делаем вывод, что кернинга в LibraryCS нет.
Я плохо представляю, как Вы собирались увеличить или уменьшить кернинг, так как он жёстко прописывается в самом шрифте в специальных таблицах кернинговых пар. Т. е. кернинг или есть, или его нет совсем, как хвоста у ослика Иа.

В том же HTML кернинг включается достаточно просто — через CSS3 свойство font-kerning или font-feature-settings:"kern".

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #3 : 26 Январь 2016, 11:13:32 »
Я понял, что Вы имеете в виду.
К сожалению, на данный момент я не нашел возможности читать информацию о кернинговых парах из файла гарнитуры (в данном случае .ttf), используя программные средства Android. Тем не менее, уверен, что каким-то образом это можно сделать.

В любом случае, даже при наличии такой информации модификация текущего алгоритма отображения займет не одну неделю (при этом алгоритм будет работать заметно медленнее, чем текущий)

P.S. В прошлом сообщении я имел в виду явное изменение межбуквенного расстояния.

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #4 : 26 Январь 2016, 13:35:45 »
А нельзя применить что-то типа
attrStr.addAttribute(TextAttribute.KERNING, TextAttribute.KERNING_ON);
или у Вас текст не является объектом класса AttributedString?

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

Ещё хотел поинтересоваться, откуда Вы взяли шрифт Canonic? Насколько я понимаю, это доведённый до ума нелюбимый многими Киприан, который также днём с огнём не сыщешь.

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #5 : 26 Январь 2016, 15:17:28 »
К сожалению, нет, не получится.
Для отображения текста не используются стандартные компоненты (вроде TextView) - отрисовка производится вручную. Положение каждой буквы рассчитывается по отдельности, поэтому для реализации кернинга необходимо уменьшать стандартное межбуквенное расстояние в соответствии со значением, взятым из таблицы кернинговых пар. Можно, конечно, создать собственную таблицу внутри приложения,но такой вариант кажется мне некорректным.

Вы даже не представляете, на каких устройствах пользователи порой пытаются запустить данное приложение (например, на электронных книгах).

Шрифт Canonic был прислан одним из пользователей около полугода назад.
« Последнее редактирование: 26 Январь 2016, 15:25:47 от Александр »

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #6 : 26 Январь 2016, 15:48:47 »
А не могли бы Вы прислать исходники? Я, если придумаю, как сделать кернинг, пришлю Вам свой вариант.

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #7 : 27 Январь 2016, 11:10:54 »
Не думаю, что имеет смысл приводить все исходники.
Конкретно участок, отвечающий за вывод текста, выглядит примерно так:

public class TextRenderer extends View {

    private TextPaint paint;

    public TextRenderer(Context context) {
        super(context);
        paint = new TextPaint();
        paint.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/Canonic.ttf"));
        paint.setTextSize(20f);
        paint.setColor(Color.parseColor("#e34234"));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        String text = "Ѓзъ ўснyхъ, и3 спaхъ, востaхъ, ћкw гDь застyпитъ мS.";
        float[] widths = new float[text.length()];
        paint.getTextWidths(text, widths);

        float y = 100f;
        float xOffset = 0f;

        for (int i = 0; i < widths.length; i++) {
            canvas.drawText(text.substring(i , i+1), xOffset, y, paint);
            xOffset += widths[i]; //Здесь
        }

    }
}

Строка, отмеченная комментарием //Здесь, отвечает за определение позиции начала следующей буквы. Именно в этой строке необходимо реализовать поправку, уменьшив xOffset на значение соответствующей кернинговой пары из таблицы.

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #8 : 03 Февраль 2016, 16:25:21 »
Здравствуйте, уважаемый Александр!
Забегая наперёд, скажу, что мне, наконец, стали ясны причины неработающего кернинга, но я нуждаюсь в Вашей помощи как опытного программиста.

Можно ли как-то средствами Java/Android (из тех, что Вы используете при открытии файла) заставить приложение читать символы из файла не в кодовой странице Windows-1251, а в обычном 8-битном виде, типа ISO 8859-1 (расширенная ASCII)? Т. е., например, вместо "[Ѓ]зъ ўснyхъ и3 спaхъ, востaхъ, ћкw гDь застyпитъ мS." нужно "[]çú ¢ñíyõú è3 ñïaõú, âîñòaõú, žêw ãDü çàñòyïèòú ìS.".
Можно, конечно, и вручную перегнать каждый символ через массив подстановок, но ведь должен же быть нормальный метод.

Дополнение
Я, наконец, нашёл конструкцию, которая работает, как мне нужно:
try {
     String filename = "001";
     String str = null;
     FileInputStream fis = openFileInput(filename);
     BufferedReader br = new BufferedReader(new InputStreamReader(fis, "ISO8859-1"));
     while ((str = br.readLine()) != null){
                //операции со строкой
            }
     fis.close();
     } catch (IOException e) {
            e.printStackTrace();
}

Этот метод реально работает! Но... со слегка модифицированными шрифтами. Можете убедиться сами, шрифт я поместил во вложения:
« Последнее редактирование: 03 Февраль 2016, 20:33:50 от Eniack »

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #9 : 04 Февраль 2016, 00:46:36 »
Уточните, что конкретно заработало и в чем состоял вопрос.

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

В чем следует убедиться из приложенного файла?

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #10 : 04 Февраль 2016, 14:46:25 »
Тут дело вот в чём. Немного предыстории.
Мне (после долгих мучений с установкой Android Studio) удалось наладить подстановку к координате "x" кернингового смещения из простого двумерного массива, в который данные загружались из отдельного файла, содержащего кернинговые пары, заблаговременно извлечённые туда из шрифта.

Всё заработало. Но тут я неожиданно обнаружил, что между некоторыми буквами (например, кириллическими "а" и "с") расстояние уменьшилось сверх меры. Т. е., помимо моего ручного кернинга действовал ещё какой-то неведомый фактор.

Я начал копаться в шрифте (с помощью программы FontCreator 6), думал, что косяк какой-то, но ничего так и не обнаружил, шрифт оказался в полном порядке. Тогда я решил удалить все кернинговые пары из шрифта, но глюк так и остался. Открыл шрифт в другом редакторе (FontForge), который при открытии написал, что, мол, шрифт содержит сразу и обычные таблицы кернинга и т. н. GPOS. Тут до меня стало потихоньку доходить.

Полез в интернеты. Где-то нашёл информацию, что помимо (или вместо) стандартных кернинговых таблиц в современных шрифтах используются таблицы GPOS — более совершенный способ хранения информации о парах. Я в FontForge сохранил шрифт без GPOS, кинул его в эмулятор Android — глюк пропал.

Оказалось, что мой FontCreator 6 — устаревшая версия и в упор не видит эти GPOS. В новой версии FontCreator 9 оказалось, вроде бы, всё нормально. Там ещё как-то зависит от формата TTF/OTF, тонкости всякие; мозги, короче, набекрень.

Так вот. Кернинг, на самом деле, работает на Android, в том числе и в Вашей программе. Но работает он согласно тупой американской логике. Дело в том, что какие-то быдлокодеры из Кремниевой долины (программистами их назвать язык не поворачивается) решили, что они умнее шрифтовых дизайнеров, и жёстко прописали в Java/Android запрет на кернинг между буквами различных языков. Именно поэтому кернинг в паре "ас" работает, а вот в паре "гD" — уже нет.

И это касается не только Андроида. На Windows кернинг между символами, принадлежащими разным языкам, прекрасно работает в таких программах как Word 2003, CorelDRAW X6 (наверно, ещё каких-то, нет возможности проверить все программы). Но вот в том же редакторе FontCreator 9 в тестовой строке он ни в какую не работает, хотя прямо тут же показывает все доступные кернинговые пары и не выводит никаких предупреждений о возможных проблемах. В общем, дурдом окончательный и бесповоротный. Я, пока докапывался до истины, чуть ума не лишился.

Создатель церковнославянской кодировки UCS8 при её создании руководствовался, прежде всего, удобством набора и совместимостью с кодовой страницей Windows-1251. И уж никак он, наверно, не полагал, что наши заокеанские "друзья" подложат нам такую свинью. И ведь самый прикол в том, что при обычном наборе кириллических текстов кернинг работает нормально. Но для кодировки цся UCS8 двуязычный кернинг — обычное дело, хотя кому из IT корпораций есть дело до какого-то там церковнославянского языка... Так что никто, скорее всего, эту тупость с кернингом в Андроиде исправлять не будет.

Теперь о возможном решении проблемы. Так как UCS8 является кодировкой, полностью умещающейся в cp1251, есть возможность читать символы из файла не как Windows-1251, а как обычную 8-битовую ASCII. То есть мы таким образом обманываем систему, заставляя её думать, будто отображаемый текст полностью на латинице.

Остаётся дело за малым: модифицировать шрифты таким образом, чтобы они могли работать в двух режимах — обычный windows-1251 и iso8859-1. Один шрифт я уже сделал (Canonic), поэтому и выложил его, чтобы Вы могли убедиться в работоспособности данного трюка. В программу можно было бы добавить чекбокс для включения/отключения кернинга, который на самом деле управлял бы кодировкой InputStreamReader.

Фокус реально работает! По крайней мере, на эмуляторе.

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #11 : 04 Февраль 2016, 17:56:32 »
Спасибо за объяснение, теперь все понятно. (Не знал, что метод getTextWidths() учитывает кернинг при определении "ширины" символов.)

Попробую потестировать на досуге.

P.S. Указанный подход загрузки файла действительно поможет решить проблему, но потребует модификации шрифтов.

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #12 : 04 Февраль 2016, 20:40:20 »
Если я правильно понял, метод getTextWidths() именно так и рассчитывает. Потому что у меня при тестировании в Android Studio точка начала левого отступа символа "с", идущего после "а", лежала на кончике буквы "а". Если бы кернинг не учитывался, то у символа "а" был бы ещё правый отступ.

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

Александр

  • Администратор
  • Старожил
  • *****
  • Сообщений: 250
    • Просмотр профиля
Re: Кернинг
« Ответ #13 : 04 Февраль 2016, 22:33:52 »
Вот тут как раз не уверен. Во-первых, мне кажется, что "ас" - не слишком удачный пример кернинговой пары (пара ли это вообще?). Во-вторых, о работающем кернинге можно судить по наличию отрицательных отступов. Никаких дополнительных расстояний данный метод не прибавляет - он рассчитывает ширину символов - от самой левой точки до самой правой.

Eniack

  • Новичок
  • *
  • Сообщений: 12
    • Просмотр профиля
Re: Кернинг
« Ответ #14 : 05 Февраль 2016, 01:41:15 »
Никаких дополнительных расстояний данный метод не прибавляет
Вы неправильно меня поняли. Я, естественно, не утверждаю, что метод getTextWidths() чего-то там прибавляет. Правый отступ у символа — прописанное в самом шрифте некоторое целое число (так же, как и левый отступ): вот на скриншоте у буквы "а" они оба по 40 единиц.

Так вот, при неработающем кернинге ширина символа рассчитывается до точки между правым отступом текущего символа и левым отступом правого символа. А при работающем кернинге ширина символа сокращается (в подавляющем большинстве случаев), уменьшая правый отступ, в том числе, до отрицательных значений.

Также привёл ещё два скрина в подтверждение того, что я ничего не придумал насчёт пары "ас". Сейчас вот специально пригляделся ещё раз к телефону: пара "ас", как и другие чисто кириллические пары, кернингуется в текущей версии "Библиотеки ЦС", а смешанные пары — нет.