Экономия места для японской кодировки? - PullRequest
6 голосов
/ 22 декабря 2010

На мой взгляд, распространенная проблема: кодировка символов в сочетании с растровым шрифтом.Большинство многоязычных кодировок имеют огромное пространство между различными типами символов и даже большим количеством неиспользуемых кодовых точек.Поэтому, если я хочу использовать их, я трачу много памяти (не только для сохранения многобайтового текста - я имею в виду специально для пробелов в моем растровом шрифте) - а VRAM в основном очень полезен ... Так что кажется единственно разумнымбыть: Использование пользовательского сопоставления на моей текстуре для символов UTF-8 (чтобы не было пустого места).НО: Это усилие похоже на использование собственной проприетарной кодировки символов (так же как и собственного порядка символов в моей текстуре).В моем конкретном случае я получил текстурное пространство для 4096 различных символов и мне нужны символы для отображения латинского языка, а также японского (это путаница с utf-8, которая поддерживает только общие кодовые страницы cjk).Была ли у кого-нибудь похожая проблема (мне действительно интересно, если нет)?Если уже есть какой-либо подход?

Редактировать: Здесь описана та же проблема http://www.tonypottier.info/Unicode_And_Japanese_Kanji/, но она не дает реального решения, как сохранить эти отображения растрового шрифта в эффективном пространстве utf-8.Так что любая дальнейшая помощь приветствуется!

Edit2:

Большое спасибо за ваш ответ.Мне очень жаль, что моя проблема не была достаточно ясно описана.

Что я действительно хочу решить, так это: диапазон Юникода CJK превышает 20000 символов.Но для правильного отображения японского текста требуется только подмножество около 2000 символов.Эти характеристики распространяются в диапазоне от U + 4E00 до U + 9FA5.Поэтому мне нужно каким-то образом преобразовать эти кодовые точки Unicode (только 2000 для японского языка) в координаты моей созданной текстуры (где я могу также упорядочить символы так, как хочу).

т.е. U + 4E03 - японский символ, но U + 4E04, U + 4E05, U + 4E06 - нет.Тогда U + 4E07 - это тоже японский персонаж.Итак, самое простое решение, которое я вижу: после символа U + 4E03 оставьте три пробела в моей текстуре (или напишите там ненужные символы U + 4E04, U + 4E05, U + 4E06), а затем напишите U + 4E07.Но это будет тратить слишком много места для текстуры (20000 символов, даже если необходимо только 2000).Так что я хочу иметь возможность вставить только мою текстуру: "... U + 4E03, U + 4E07 ...".Но я не знаю, как написать свою функцию displayText, потому что я не могу знать, где находятся текстурные координаты глифа, который я хочу отобразить.Там будет хэш-карта или что-то вроде этого, но я понятия не имею, как хранить эти данные (было бы бесполезно писать для каждого символа что-то вроде ... {U + 4E03, 128}, {U + 4E07,129} ... чтобы заполнить hasmap).

К вопросам: 1) Нет конкретного формата - поэтому я сам напишу функцию displayText.2) Нет причин против Unicode - только проблема с диапазоном CJK для моего растрового шрифта.3) Я думаю, это обычно не зависит от платформы и языка, но в моем случае я использую C ++ с OpenGL на Mac OS X / iOS.

Большое спасибо за вашу помощь!Если у вас есть какие-либо дальнейшие идеи для этого, это мне очень поможет!

Ответы [ 6 ]

3 голосов
/ 27 декабря 2010

Какую реальную проблему вы хотите решить?

Неужели строка в кодировке UTF-8 занимает три байта на символ?Если да, переключитесь на UTF-16.В противном случае не вините UTF-8.(Объяснение: UTF-8 - это просто алгоритм для преобразования последовательности целых чисел в последовательность байтов. Он не имеет ничего общего с группировкой символов в кодовых страницах. Это, в свою очередь, то, что кодовые точки Unicode являютсяfor.)

Неужели кодовые точки Unicode распределены по многим «кодовым страницам» (где «кодовая страница» означает блок из 256 смежных кодовых точек Unicode)?Если да, придумайте отображение из кодовых точек Unicode (0x000000 - 0x10FFFF) в меньший набор целых чисел.С точки зрения памяти это должно стоить не более 4 байтов, умноженных на количество символов, которое вам действительно нужно.Время поиска составило бы приблизительно 24 обращения к памяти, 24 целочисленных сравнения и 24 инструкции ветвления.(На самом деле это будет бинарный поиск в древовидной карте.) И если это слишком дорого, вы можете использовать отображение на основе хеш-таблицы.

Это что-то еще?Затем, пожалуйста, приведите несколько примеров, чтобы лучше понять вашу проблему.

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

  1. Приходится ли вам использовать определенный формат растрового шрифта или вы сами напишите функцию displayText?
  2. Есть ли какая-либо причина против использования Юникода для всехстрок и преобразовать их в оптимизированную для растровых изображений кодировку только для того времени, когда вы визуализируете текст?Преобразование кодировки, конечно, будет внутренним по отношению к методу displayText и не будет видимым для нормального кода приложения.
  3. Просто не представляет интереса: специфична ли проблема для определенного языка программирования или среды?

Обновление :

Я предполагаю, что вашей основной проблемой является какая-то функция, подобная этой:

Rectangle position(int codepoint)

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

  1. Загрузка всех растровых изображений и определение их размеров.Результатом этого шага является карта из целых чисел в пары (ширина, высота).
  2. Вычислите правильную компоновку для изображений персонажей на большой картинке и запомните, где был размещен каждый символ.Сохранить большую картинку.Сохраните отображение из кодовых точек в (x, y, ширина, высота) в другой файл.Это может быть текстовый файл или, если у вас нет места на диске, бинарный файл.Детали не имеют значения.

Функция displayText будет тогда работать следующим образом:

void displayText(int x, int y, String s) {
  for (char c : s.toCharArray()) { // TODO: handle code points correctly
    int codepoint = c;
    Rectangle position = positions.get(codepoint);
    if (position != null) {
      // draw bitmap
      x += position.width;
    }
  }
}

Map<Integer, Rectangle> positions = loadPositionsFromFile();

Теперь единственная оставшаяся проблема - как эта карта может быть представленав памяти, используя как можно меньше памяти, и при этом быть достаточно быстрым.Это, конечно, зависит от вашего языка программирования.

Представление в памяти может быть несколькими массивами, которые содержат x, y, width, height.Для каждого элемента должно быть достаточно 16-битного целого числа.И, вероятно, вам нужно всего лишь 8 бит для ширины и высоты в любом случае.Затем другой массив отобразит кодовую точку на индекс в positionData (или какое-то специальное значение, если кодовая точка недоступна).Это будет массив из 20000 16-битных целых чисел, так что в итоге вы получите:

  • 2000 * (2 + 2 + 1 + 1) = 12000 байт для positionX, positionY, positionWidth и positionHeight
  • 20000 * 2 = 40000 байт для codepointToIndexInPositionArrays, если вместо карты используется массив.

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

2 голосов
/ 28 декабря 2010

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

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

Я думаю, что лучший способ решить эту проблему - использовать существующую реализацию(UTF16, UTF8 ...) Это будет намного менее подвержено ошибкам, чем реализация собственного кодирования Хаффмана, чтобы сэкономить немного места.Дисковое пространство и полоса пропускания дешевы, ошибок, которые раздражают клиентов или менеджеров, нет.Я уверен, что теоретически кодирование Хаффмана будет наиболее эффективным (без потерь) кодированием из возможных, но не самым практичным для этого приложения.Проверьте ссылку, хотя, это может помочь с некоторыми из этих концепций.

-Брайан Дж. Стинар-

1 голос
/ 30 декабря 2010

Бумага в значительной степени устарела, это уже не 1980 год, поиск битов не является обязательным требованием практически любого приложения для отображения.При разработке приложения, например, iPhone, вы должны планировать l10n на нескольких языках, поэтому экономить несколько бит только на японском языке немного бессмысленно.

Япония по-прежнему использует Shift-JIS, потому что, как и Китай с GB18030, HongВ отличие от BIG5 и т. Д., Они имеют большой, стабильный и эффективный пул ресурсов, уже заблокированный в кодировках локалей.Миграция на Unicode требует переписывания значительного количества инструментов инфраструктуры и последующего дополнительного тестирования.

Если вы посмотрите на iPod, он экономит биты, поддерживая только латиницу, китайский, японский и корейский языки, пропуская тайский идругие скрипты.По мере того, как цены на память снижались, а объем памяти увеличивался с iPhone, Apple смогла добавить поддержку большего количества сценариев.

UTF-8 - это способ сэкономить место, использовать UTF-8 для хранения и преобразовать в UCS-2или выше для более удобной манипуляции и отображения.Различия между Shift-JIS и Unicode очень незначительны.

1 голос
/ 22 декабря 2010

UTF-8 обычно очень эффективная кодировка.Если ваше приложение ориентировано в основном на Азию и другие регионы с многобайтовыми наборами символов, вы можете получить больше пользы от использования UTF-16.Конечно, вы могли бы написать свою собственную кодировку, но это не сэкономит вам столько данных и обеспечит вам много работы.

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

0 голосов
/ 26 декабря 2010

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

0 голосов
/ 22 декабря 2010

Только в китайском языке более 4096 символов, и я говорю не о пунктуации, а о символах, которые используются для формирования слов. От Википедия :

Количество китайских иероглифов, содержащихся в словаре Канси, составляет приблизительно 47 535, хотя большое количество из них - редко используемые варианты, накопленные в истории.

Несмотря на то, что многие из них используются редко, даже если бы 90% не были необходимы, вы все равно исчерпали бы свою квоту. (Я думаю, что фактическое число, используемое в современном тексте, где-то около 10 - 20 тыс.).

Если вы заранее знаете, какие символы вам понадобятся, чтобы использовать лучшую ставку, возможно, создайте таблицу косвенных кодов Unicode для индексов вашей текстуры. Тогда вам нужно всего лишь добавить столько символов в вашу текстуру, сколько вы фактически используете. Я считаю, что Flash (и некоторые PDF-файлы) делают что-то подобное внутри себя.

...