如何将位图字体从 C 标头格式转换为原始位

How to convert a bitmap font from C header format to raw bits

本文关键字:格式 转换 原始 位图 字体      更新时间:2023-10-16

我有一个 C 头文件,其中包含 10x12 像素位图字体字符,位于 2x12 数组中(用于单色 LCD)。 这浪费了每隔一个字节的较低 6 位,更不用说由于必须跳过填充而更难渲染了。

将其

转换为没有填充位的简单序列化位的最简单方法是什么?

我看到的解决方案有很多复杂的位敲击。 有没有一种简单的方法来执行此操作?

0x00,0x00,  /*  ................  */
0x30,0x00,  /*  ..@@............  */
0x78,0x00,  /*  .@@@@...........  */
0x48,0x00,  /*  .@..@...........  */
0xCC,0x00,  /*  @@..@@..........  */
0xCC,0x00,  /*  @@..@@..........  */
0xCC,0x00,  /*  @@..@@..........  */
0xFC,0x00,  /*  @@@@@@..........  */
0xCC,0x00,  /*  @@..@@..........  */
0xCC,0x00,  /*  @@..@@..........  */
0x00,0x00,  /*  ................  */
0x00,0x00   /*  ................  */

好吧,10 × 12 = 120,你可以准确地在 15 字节中存储 120 个像素。每 5 个字节编码 4 行像素。

你得到的本质上是一个 8x15 的稀疏矩阵。

有一个提升库 - uBLAS - 来帮助你处理稀疏矩阵。例如,如果您的字体尺寸发生变化,这将有所帮助。

这个问题也可能有所帮助。

至于"复杂的位敲击"... 是的,这很复杂,但是如果您将打包的字节和索引写到它们来自的解压缩数组中,那么很容易弄清楚如何构造每个值......

|........|........|........|........|........|
|00000000|11222222|22334444|44445566|66666677|

上述循环重复3次。

char a[24] = {
    0x00,0x00,  /*  ................  */
    0x30,0x00,  /*  ..@@............  */
    0x78,0x00,  /*  .@@@@...........  */
    0x48,0x00,  /*  .@..@...........  */
    0xCC,0x00,  /*  @@..@@..........  */
    0xCC,0x00,  /*  @@..@@..........  */
    0xCC,0x00,  /*  @@..@@..........  */
    0xFC,0x00,  /*  @@@@@@..........  */
    0xCC,0x00,  /*  @@..@@..........  */
    0xCC,0x00,  /*  @@..@@..........  */
    0x00,0x00,  /*  ................  */
    0x00,0x00   /*  ................  */
};
void pack( char ap[15], const char a[24] )
{
    ap[0] = a[0];
    ap[1] = a[1] | (a[2] >> 2 );
    ap[2] = (a[2] << 6) | (a[3] >> 2 ) | (a[4] >> 4);
    ap[3] = (a[4] << 4) | (a[5] >> 4) | (a[6] >> 6);
    ap[4] = (a[6] << 2) | (a[7] >> 6);
    ap[5] = a[8];
    ap[6] = a[9] | (a[10] >> 2 );
    ap[7] = (a[10] << 6) | (a[11] >> 2 ) | (a[12] >> 4);
    ap[8] = (a[12] << 4) | (a[13] >> 4) | (a[14] >> 6);
    ap[9] = (a[14] << 2) | (a[15] >> 6);
    ap[10] = a[16];
    ap[11] = a[17] | (a[18] >> 2 );
    ap[12] = (a[18] << 6) | (a[19] >> 2 ) | (a[20] >> 4);
    ap[13] = (a[20] << 4) | (a[21] >> 4) | (a[22] >> 6);
    ap[14] = (a[22] << 2) | (a[23] >> 6);
}

如果你愿意,你可以在一个小循环中做上述操作,以减少犯错的范围...... 只需从 0 循环到 2,并相应地推进数组。 你知道,有点像这样(除了你需要适当的指针):

for( int i = 0; i < 3; i++ ) {
    ap[0] = a[0];
    ap[1] = a[1] | (a[2] >> 2 );
    ap[2] = (a[2] << 6) | (a[3] >> 2 ) | (a[4] >> 4);
    ap[3] = (a[4] << 4) | (a[5] >> 4) | (a[6] >> 6);
    ap[4] = (a[6] << 2) | (a[7] >> 6);
    ap += 5;
    a += 8;
}

我希望我把所有这些转变都做对了=)

当然,

这正是JBIG CODEC旨在处理的问题 - 但会涉及大量的位敲击。

使用字典编码算法处理0的运行长度,您可能还会获得不错的结果。

简化版本可以创建一个生产者消费者,一次一个位,使位爆炸保持在理智的水平。 这是我最终做的事情:

#define CHAR_W 10
#define CHAR_H 12
#define NUM_CHARS 100
#define CEILING(x,y) (((x) + (y) - 1) / (y))
#define BYTES CEILING(CHAR_W, 8)
#define BIT(x, n) ( ((1 << n) & x) >> n )
#define COPYBIT(b,x,n) (((0x1 & b) << n) | x)
#define CHAR_BYTES CEILING(CHAR_H * CHAR_W, 8)
#define OUTBYTES NUM_CHARS * CHAR_BYTES
int main()
{
    int totinbit = 0;
    int locinbit = 0;
    int locoutbit = 7;  // start with msb 
    int totoutbit = 0;
    int bytes = BYTES;
    unsigned char c = 0;
    unsigned char o = 0;
    unsigned char buf[OUTBYTES];
    while (totoutbit < NUM_CHARS * CHAR_H * CHAR_W)
    {
        c = fontArray[totinbit / 8];
        locinbit = 7 - totinbit % 8;
        o = COPYBIT(BIT(c,locinbit),o,locoutbit);
        // reset out counter, full byte produced
        if (--locoutbit < 0)
        {
            locoutbit = 7;
            buf[totoutbit  / 8] = o;
            o = 0;
        }
        // skip over the padding bits
        if ((totoutbit % CHAR_W) == (CHAR_W - 1))
            totinbit =  CEILING(totinbit,8) * 8 - 1;
        totinbit++;     
        // character boundary
        if ( (totinbit % (bytes * 8 * CHAR_H)) == 0 && totinbit > 0)
        {
                            // pad the last byte in the character if necessary
            if (locoutbit != 7)
                    locoutbit = 7;
        }
        totoutbit++;

        }
 // at this point buf contains the converted bitmap array
}