Как преобразовать растровый шрифт из формата заголовка C в необработанные биты

У меня есть заголовочный файл C, который содержит символы растрового шрифта размером 10x12 пикселей в массиве 2x12 (для монохромного ЖК-дисплея). Это тратит впустую младшие 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   /*  ................  */

person MandoMando    schedule 25.09.2012    source источник
comment
Нет, нет способа сериализовать биты без большого количества битов. И я думаю, что дополнительное дополнение сделает код проще, а не сложнее.   -  person Mark Ransom    schedule 26.09.2012


Ответы (5)


Ну, 10 12 = 120, и вы можете хранить 120 пикселей ровно в 15 байтах. Каждые 5 байт кодируют 4 строки пикселей.

person Kerrek SB    schedule 25.09.2012
comment
Действительно? два плюса за указание на арифметику и отсутствие реального ответа? - person MandoMando; 26.09.2012

По сути, у вас есть разреженная матрица 8x15.

Есть библиотека повышения - uBLAS - чтобы помочь вам справиться с разреженными матрицами. Это может помочь, например, если размеры вашего шрифта изменятся.

Этот вопрос также может быть полезен.

person Carl    schedule 25.09.2012

Что касается «сложной битовой переборки»… Да, это сложно, но если вы запишете свои упакованные байты и индекс в неупакованный массив, откуда они берутся, достаточно легко понять, как построить каждое значение ...

|........|........|........|........|........|
|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;
}

Надеюсь, я все правильно понял =)

person paddy    schedule 25.09.2012
comment
спасибо за публикацию этого. Я надеялся на что-то более общее, чтобы работать и с другими размерами символов. Хотя наводит на мысль. - person MandoMando; 26.09.2012
comment
Ах, да... Ну, посмотрите на операции, которые я сделал, и объедините их с тем, как я выписал эти индексы. Это будет непросто, но единственная реальная хитрость — это последний байт (если ширина символа не кратна 8 битам). Вот когда вы «дрейфуете» свои битовые сдвиги. - person paddy; 27.09.2012
comment
Да, в итоге я выталкивал по одному биту и добавлял в массив dst. Идея смещения нескольких битов в разных местах в общем решении вызывала у меня головную боль. Дрейф действительно вступает в игру, решение, которое я опубликовал, имеет небольшую проблему, когда WxH не кратно 8, но 8 делит остаток. Таким образом, дрейф суммируется и выравнивается по границе байта. В любом случае, спасибо за вдохновение! - person MandoMando; 27.09.2012

Это, конечно, именно та проблема, для решения которой предназначен КОДЕК JBIG, но быть чудовищным количеством ударов по битам.

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

person marko    schedule 26.09.2012

Упрощенная версия может создать производителя-потребителя, работающего по одному биту за раз, что удерживает бит на нормальном уровне. Вот что я в итоге сделал:

#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
}
person MandoMando    schedule 26.09.2012