在我看来,一个常见问题是:字符编码与位图字体结合使用。大多数多语言编码在不同的字符类型之间有很大的空间,甚至还有很多未使用的代码点。因此,如果我想使用它们,我会浪费大量内存(不仅仅是为了保存多字节文本 - 我的意思是专门用于我的位图字体中的空格) - 而且VRAM大部分都非常有价值......所以唯一合理的东西似乎要:在我的纹理上使用自定义映射,即UTF-8字符(这样就不会浪费空间)。但是:这种努力似乎与使用自己的专有字符编码相同(因此我的纹理中也有自己的字符顺序)。在我的特殊情况下,我获得了4096个不同角色的纹理空间,并且需要角色来显示拉丁语言和日语(它是一个混乱的utf-8,只支持generall cjk代码页)。有人有类似的问题(我真的很想知道,如果没有)?如果已经有任何办法吗?
编辑:这里描述了同样的问题http://www.tonypottier.info/Unicode_And_Japanese_Kanji/但它并没有提供一个真正的解决方案如何将这些bitmapfont映射保存到utf-8空间效率。所以欢迎任何进一步的帮助!
EDIT2:
非常感谢您的回答。对不起,我的问题描述得不够明确。
我真正想要解决的问题是:CJK Unicode范围超过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函数 - 因为我不知道我想要显示的字形的纹理坐标在哪里。会有一个hashmap或类似的东西,但是我不知道如何存储这些数据(为每个字符编写会很麻烦...... {U + 4E03,128},{U + 4E07, 129} ...填写hasmap)。
问题: 1)没有特定的格式 - 所以我将自己编写displayText函数。 2)没有理由反对unicode - 它只是我的bitmapfont的CJK范围问题。 3)我认为,这通常是平台和语言无关,但就我而言,我在Mac OS X / iOS上使用C ++和OpenGL。
非常感谢你的帮助!如果您对此有任何进一步的想法,那对我来说真的很有帮助!
答案 0 :(得分:3)
您想要解决的真正问题是什么?
UTF-8编码的字符串是否占用每个字符三个字节?如果是,请切换到UTF-16。否则不要责怪UTF-8。 (解释:UTF-8只是一个将整数序列转换为字节序列的算法。它与代码页中的字符分组无关。这反过来又是 Unicode代码点是为了。)
Unicode代码点是否分布在许多“代码页”上(其中“代码页”表示256个相邻Unicode代码点的块)?如果是,则发明从Unicode代码点(0x000000 - 0x10FFFF)到较小的整数集的映射。在内存方面,这应该花费不超过你真正需要的字符数的4个字节。查询时间约为24次内存访问,24次整数比较和24次分支指令。 (事实上,这将是树形图中的二进制搜索。)如果这太贵了,你可以使用基于哈希表的映射。
还有别的吗?那么请给我们一些例子,以便更好地理解你的问题。
据我所知,您应该编写一个小实用程序,将您想要在应用程序中使用的一组Unicode代码点作为输入,然后生成用于显示文本的代码和数据。这引出了一些问题:
displayText
函数?displayText
方法的内部,对普通应用程序代码不可见。<强>更新强>:
我假设你的主要问题是这样的一些功能:
Rectangle position(int codepoint)
如果我必须这样做,我会从每个角色有一个位图开始。位图的文件名将是代码点,因此可以轻松地重新生成“大图”,以防您找到所需的更多字符。准备工作包括以下步骤:
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位整数的数组,所以总结一下,你有:
positionX
,positionY
,positionWidth
和positionHeight
codepointToIndexInPositionArrays
的40000字节,如果您使用数组而不是地图。与位图本身的大小相比,这应该足够小。并且由于数组不会更改,因此它们可以位于只读存储器中。
答案 1 :(得分:2)
我认为编码此数据的最有效(无损)方法是使用Huffman encoding来存储您的文档信息。这是一个经典的信息论问题。您需要执行映射以从压缩空间转到字符空间。
此技术将根据每个文档的字符频率(或您选择应用它的任何域/文档)尽可能高效地压缩文档。只会存储您使用的字符,并且它们将以有效的方式存储,与使用频率成正比。
我认为解决这个问题的最佳方法是使用现有的实现(UTF16,UTF8 ......)这比实现自己的Huffman编码更不容易出错,以节省一点空间。磁盘空间和带宽很便宜,让客户或经理感到愤怒的错误不是。我相信霍夫曼编码理论上可能是最有效(无损)编码的可能,但对于这个应用来说并不是最实用的。查看链接,这可能有助于其中一些概念。
-Brian J. Stinar -
答案 2 :(得分:1)
UTF-8通常是一种非常有效的编码。如果您的应用程序主要关注亚洲和其他具有多字节字符集的区域,那么使用UTF-16可能会从中受益更多。您当然可以编写自己的编码,但它不会为您节省太多数据,它会为您提供大量工作。
如果你真的需要压缩你的数据(我想知道是否和为什么)你最好使用一些算法来压缩你的UTF数据。大多数算法在较大的数据块上工作效率更高,但也有压缩小块文本的算法。如果您探索这些内容而不是定义自己的编码,我认为您将节省很多时间。
答案 3 :(得分:1)
这篇论文已经过时了,不再是1980年了,几乎任何显示应用程序都不需要搜索位。在开发应用程序时,例如, iPhone你需要为多种语言规划l10n,所以只为日语节省一些比特是没有意义的。
日本仍然使用Shift-JIS,因为像中国这样的GB18030,香港的BIG5等,他们有一个庞大,稳定,高效的资源池已经锁定在现场编码中。迁移到Unicode需要重新编写大量的框架工具以及随之而来的附加测试。
如果你看一下iPod,它只会支持拉丁语,中文,日语和韩语,跳过泰语和其他脚本,从而节省了比特。随着iPhone的内存价格下降和存储量的增加,Apple已经能够增加对更多脚本的支持。
UTF-8是节省空间的方法,使用UTF-8进行存储并转换为UCS-2或更高版本,以便更方便地操作和显示。 Shift-JIS和Unicode之间的差异非常小。
答案 4 :(得分:0)
单独的中国人有超过4096个字符,我不是说标点符号,而是用来形成单词的字符。来自Wikipedia:
康熙字典中包含的汉字数量约为47,035,尽管其中大部分都是历史上积累的变体。
即使很少使用这些,即使不需要90%,你仍然会耗尽你的配额。 (我认为现代文本中使用的实际数字大约在10到20k之间。)
如果您事先知道您需要使用哪个字符,最好的选择可能是创建一个Unicode代码点的间接表来索引到您的纹理。然后你只需要在你实际使用的纹理中放入尽可能多的字符。我相信Flash(和一些PDF)在内部做了类似的事情。
答案 5 :(得分:0)
您可以使用多个位图并按需加载它们,而不是尝试包含所有可能字符的单个位图。