У меня есть файл заголовка C, который содержит символы растрового шрифта 10×12 пикселей в массиве 2×12 (для монохромного ЖК-дисплея). Это тратит впустую младшие 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, и вы можете хранить 120 пикселей в 15 байтах, точно. Каждые 5 байтов кодируют 4 строки пикселей.
Что касается «сложного разбивания битов» … Да, это сложно, но если вы запишите свои упакованные байты и индекс в распакованный массив, откуда они берутся, то достаточно просто решить, как создать каждое значение …
|........|........|........|........|........|
|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;
}
Я надеюсь, что я получил все эти изменения правильно =)
То, что у вас есть, по сути, 8×15 разреженная матрица.
Есть буст библиотека — uBLAS — чтобы помочь вам иметь дело с разреженными матрицами. Это поможет, например, при изменении размеров шрифта.
Этот вопрос также может помочь
Это, конечно, именно та проблема, 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
}