我正在开发一个嵌入式项目(ARM7)。在我的应用程序中,我必须存储大量的中文字符,这些中文字符浪费了大约300k的闪存。当前的字体编码是Unicode,每个字符包含22个字节,因为每个字形都是12 * 12加上左侧和底侧的一个行空间,这使得它成为169像素(22个字节)(参见示例)。例如,这个汉字的Unicode
如下: / * unicode5939 * / 0x40,0x44,0x4c,0x54,0x64,0xff,0xff,0x44, 0x54,0x4c,0x44,0x40,0x0,0x8,0x11,0x11, 0x0,0x8,0x82,0x20,0x4,0x0。
当前的Unicode是这样的:字形的上8行完全等于Unicode的前13个字节(基于列而不是基于行,从右上方)。其余的9个字节代表字形的5个底部行(从左侧看,右侧逐列,在字节中放置0和1,直到字节变满,依此类推)。
如果我们对此Unicode(按位)执行RLE压缩,则结果需要超过22个字节来存储每次运行的重复次数(就我手工完成而言)。所以我想做另一种压缩。任何线索?
答案 0 :(得分:2)
通过不为每个字形存储空行,您将获得近20%的改善。
12x12而不是13x13 = 18字节而不是22。
答案 1 :(得分:1)
(不是实际答案,但我需要更多空间而不是评论)
嗯,至少13 * 13适合22个字节(它是169位,因此是21 1/8字节)。当按字节排列时,它看起来像这样:
01000000 01000 00010
01000100 01000 00010
01001100 00100 00100
01010100 00010 01000
01100100 00001 10000
11111111 00000 00000 Reordered by groups of five bits,
11111111 00000 <- 00000 <--------------------------+
01000100 00001 10000 flipped again |
01010100 00010 01000 |
01001100 00100 00100 |
01000100 01000 00010 |
01000000 01000 00010 |
00000000 00000 00000 |
00001000 -> 00010000 <- Bottom 9 bytes reversed: \ |
00010001 -> 10001000 | |
00010001 -> 10001000 | |
00000000 -> 00000000 | |
00001000 -> 00010000 +--+
10000010 -> 01000001 |
00100000 -> 00000100 |
00000100 -> 00100000 |
00000000 -> 0 (only one useful bit) /
至少前13个字节肯定看起来像角色的前8行(右上方)。对于底部9个字节,一旦反转,它们可以由5位组布局,看起来像底部。
或者更可读的是,它们都是这样编码的:
现在回答实际问题,我确信尝试单独压缩字形是一种灾难。由于缺乏存储未压缩数据的空间,因此无法在一个块中压缩所有块。因此,压缩需要在X字形块中完成,并使用缓存系统进行解压缩。
答案 2 :(得分:0)
甚至可以使用例如per / glyph来处理字体压缩。比较说4位邻域的算术编码:
[ 4 ] [ 3 ] [ 2 ]
[ 1 ] ( x )
像素p1,p2,p3,p4的每个邻域编码x == 0对x == 1的概率,其在处理比特'x'之后被更新;与霍夫曼编码器不同,算术编码器能够以比单个比特更小的单位压缩符号,这是香农信息理论给出的限制。
Context, count bits per symbol
Zeros[ 0] = 45 Ones[ 0] = 4 19.987
Zeros[ 1] = 7 Ones[ 1] = 4 10.402
Zeros[ 2] = 6 Ones[ 2] = 0 0.000
Zeros[ 3] = 2 Ones[ 3] = 2 4.000
Zeros[ 4] = 6 Ones[ 4] = 5 10.934
Zeros[ 5] = 0 Ones[ 5] = 1 0.000
Zeros[ 6] = 2 Ones[ 6] = 0 0.000
Zeros[ 7] = 9 Ones[ 7] = 4 11.576
Zeros[ 8] = 5 Ones[ 8] = 13 15.343
Zeros[ 9] = 1 Ones[ 9] = 3 3.245
Zeros[10] = 4 Ones[10] = 0 0.000
Zeros[11] = 1 Ones[11] = 3 3.245
Zeros[12] = 2 Ones[12] = 2 4.000
Zeros[13] = 1 Ones[13] = 0 0.000
Zeros[14] = 1 Ones[14] = 5 3.900
Zeros[15] = 3 Ones[15] = 3 6.000
Total 92.634 bits = 12 bytes
vs. no context,
Zeros = 95 Ones = 49 133.212 bits = 17 bytes
显而易见的问题是如何初始化数组:
1)使用固定的,即频率的静态模型
2)使用完全自适应模型,假设开始时有50:50的机会
3)使用一组(2-256?)固定模型,最好地表征字形
4)从预先计算的集合中开始一些模型并更新
一个完整的模型需要32个字节来编码0..169的值,因此除非非常强烈(并且巧妙地)压缩,否则不能用字符传递。
修改强> 如果使用单个(或非常少的全局静态表),也可以将表放大到5,6,7像素的邻域,或者将像素位置的信息嵌入到表中(这种方法无法编码条件'x是在底线'):
[ B ] [ C ] [ D ], where A,B,C,D = 00 for 'white'
[ A ] (x) 11 for 'black'
01/10 for pixel outside canvas
or
[ 1 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] + [ x is next to border? ]
[ 0 ] [ 2 ] (x)
进一步阅读:
- Fax Compression / JBIG
- Arithmetic Coding