различия в растровых изображениях или растровых изображениях шрифтов и текстовом отображении на 3,5-дюймовом ЖК-дисплее TFT

Я использую ЖК-дисплей 3.5: TFT с Arduino Uno и библиотекой от производителя, библиотекой KeDei TFT. Библиотека поставлялась с таблицей растровых шрифтов, которая огромна для небольшого объема памяти Arduino Uno, поэтому я искал альтернативы.

Я столкнулся с тем, что, похоже, не существует стандартного представления, и некоторые таблицы растровых шрифтов, которые я обнаружил, работают нормально, а другие отображаются как странные каракули и метки, или отображаются вверх ногами, или отображаются с перевернутыми буквами. Написав простое приложение для отображения некоторых символов, я наконец понял, что разные растровые изображения используют разную ориентацию символов.

Мой вопрос

Каковы правила, стандарты или ожидаемые представления битовых данных для растровых шрифтов? Почему кажется, что с растровыми шрифтами используется несколько разных ориентаций текстовых символов?

Мысли о вопросе

Это связано с разными целевыми устройствами, такими как драйвер дисплея Windows или драйвер дисплея Linux, по сравнению с драйвером дисплея Arduino TFT LCD с «голым металлом»?

Какие критерии используются для определения конкретного представления растрового шрифта в виде серии значений без знака char? Имеют ли различные типы растровых устройств, такие как ЖК-дисплей TFT и его контроллер, различную последовательность битов при рисовании на поверхности дисплея путем установки цветов пикселей?

Какие другие возможные представления растровых шрифтов, требующие преобразования, которые моя версия библиотеки в настоящее время не предлагает, существуют?

Есть ли какой-то другой метод, отличный от подхода, который я использую, чтобы определить, какое преобразование необходимо? В настоящее время я подключаю таблицу растровых шрифтов к тестовой программе и распечатываю набор символов, чтобы посмотреть, как это выглядит, а затем точно настраиваю преобразование, тестируя с помощью Arduino и ЖК-экрана TFT.

Мой опыт до сих пор

Библиотека KeDei TFT поставлялась с таблицей растровых шрифтов, которая была определена как

const unsigned char font_table_16_col[96][16] = {
    { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },/*" ",0*/
    { 0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x38,0x38,0x00,0x00 },/*"!",1*/
    { 0x00,0xD8,0xFC,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },/*""",2*/
    { 0x00,0x00,0x00,0x6C,0x6C,0x6C,0xFF,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x00,0x00 },/*"#",3*/
    { 0x00,0x00,0x18,0x3C,0x7E,0x7E,0x1E,0x1C,0x38,0x78,0x78,0x7E,0x7E,0x3C,0x18,0x18 },/*"$",4*/
    { 0x00,0x00,0x00,0x66,0x6F,0x3F,0x3F,0x3F,0x7E,0xF8,0xFC,0xFC,0xFC,0x66,0x00,0x00 },/*"%",5*/
...

Я не полностью знаком со стандартными описаниями растровых шрифтов, однако я думаю об этом как о растровом шрифте 8x16, в котором каждый символ имеет ширину 8 пикселей и высоту 16 пикселей, или растровый шрифт 8x16.

Из-за размера этой таблицы и небольшого объема памяти Arduino Uno я начал искать другие растровые шрифты, которые были бы разборчивыми и при этом занимали бы меньше памяти. См. уменьшение память, необходимая для библиотеки KeDei TFT, используемой с дисплеем 3.5 TFT с Arduino

Я надеялся найти что-то вроде растрового шрифта 6x6, чтобы определение таблицы растровых шрифтов изменилось с const unsigned char font_table_16_col[96][16] = { на const unsigned char font_table_16_col[96][6] = {, что освободило бы значительный объем памяти. И эксперименты с сокращением таблицы путем удаления строчных букв показали, что это тоже помогло.

Найти альтернативные растровые шрифты оказалось сложнее, чем я думал, представляя себе кого-то с кладезью растровых шрифтов где-то в репозитории GitHub, которого легко найти с помощью поиска или двух.

Я столкнулся с тем, что, хотя я нашел несколько разных примеров растровых шрифтов, не все из них, похоже, совместимы с моим конкретным 3,5-дюймовым ЖК-дисплеем TFT.

Например, вот представления четырех разных растровых шрифтов, показывающие биты растровых изображений для двух символов, восклицательный знак (!) и двойная кавычка (). Кажется, что 5x8 повернут по часовой стрелке на 90 градусов. 8x8 и 16x8 кажутся правильно ориентированными, а 13x8 кажутся перевернутыми.

символьное представление образцов растрового шрифта, показывающее различия

Генерация приведенного выше растрового представления

Представления растрового шрифта на изображении выше, показывающие различия в ориентации текстовых символов, были сгенерированы простым графическим интерфейсом Windows и отображены с тире (-), представляющим нулевое значение бита, и звездочкой (*), представляющим битовое значение 1. , Это вывод приложения Microsoft Windows с графическим интерфейсом, чей WM_PAINT обработчик сообщений, рисующий отображаемое изображение, выглядит следующим образом:

int paintFontDisplay(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    SetTextAlign(hdc, TA_CENTER);

    RECT rect;
    GetClientRect(hWnd, &rect);

    //Logical units are device dependent pixels, so this will create a handle to a logical font that is 48 pixels in height.
    //The width, when set to 0, will cause the font mapper to choose the closest matching value.
    //The font face name will be Impact.
    HFONT hFont = CreateFont(24, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
        CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, FIXED_PITCH, TEXT("Courier"));
    SelectObject(hdc, hFont);

    // TODO: Add any drawing code that uses hdc here...

    int iFirst = 0;
    int iLast = 10;

    POINT outPoint;
    outPoint.x = rect.left + 80;
    outPoint.y = rect.top + 20;
    for (int i = iFirst; i < iLast; i++) {
        for (int j = 0; j < 5; j++) {
            std::wstring charRep;
            for (unsigned char k = 0x80; k; k >>= 1) {
                if (font_table_5_col[i][j] & k) {
                    charRep += '*';
                }
                else {
                    charRep += '-';
                }
            }
            TextOut(hdc, outPoint.x, outPoint.y, charRep.c_str(), charRep.length());
            outPoint.y += 20;
        }
        outPoint.y += 20 + 20 * 11;
    }

    outPoint.x = outPoint.x + 200;
    outPoint.y = rect.top + 20;
    for (int i = iFirst; i < iLast; i++) {
        for (int j = 0; j < 8; j++) {
            std::wstring charRep;
            for (unsigned char k = 0x80; k; k >>= 1) {
                if (font_tabledrawGlyph()col[i][j] & k) {
                        charRep += '*';
                }
                else {
                    charRep += '-';
                }
            }
            TextOut(hdc, outPoint.x, outPoint.y, charRep.c_str(), charRep.length());
            outPoint.y += 20;
        }
        outPoint.y += 20 + 20 * 8;
    }

    outPoint.x = outPoint.x + 200;
    outPoint.y = rect.top + 20;
    for (int i = iFirst; i < iLast; i++) {
        for (int j = 0; j < 13; j++) {
            std::wstring charRep;
            for (unsigned char k = 0x80; k; k >>= 1) {
                if (font_table_13_col[i][j] & k) {
                    charRep += '*';
                }
                else {
                    charRep += '-';
                }
            }
            TextOut(hdc, outPoint.x, outPoint.y, charRep.c_str(), charRep.length());
            outPoint.y += 20;
        }
        outPoint.y += 20 + 20 * 3;
    }

    outPoint.x = outPoint.x + 200;
    outPoint.y = rect.top + 20;
    for (int i = iFirst; i < iLast; i++) {
        for (int j = 0; j < 16; j++) {
            std::wstring charRep;
            for (unsigned char k = 0x80; k; k >>= 1) {
                if (font_table_16_col[i][j] & k) {
                    charRep += '*';
                }
                else {
                    charRep += '-';
                }
            }
            TextOut(hdc, outPoint.x, outPoint.y, charRep.c_str(), charRep.length());
            outPoint.y += 20;
        }
        outPoint.y += 20;
    }

    EndPaint(hWnd, &ps);

    return 0;
}

Первые несколько строк таблиц растровых шрифтов выглядят следующим образом:

//  following table from URL https://forum.arduino.cc/t/font-generation-for-bitmaps/161582/11
const unsigned char font_table_5_col[96][5] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00 } // 20
    ,{ 0x00, 0x00, 0x5f, 0x00, 0x00 } // 21 !
    ,{ 0x00, 0x07, 0x00, 0x07, 0x00 } // 22 "
    ,{ 0x14, 0x7f, 0x14, 0x7f, 0x14 } // 23 #
    ,{ 0x24, 0x2a, 0x7f, 0x2a, 0x12 } // 24 $

// See https://github.com/dhepper/font8x8
const unsigned char font_tabledrawGlyph()col[96][8] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0020 (space)
    { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00 },   // U+0021 (!)
    { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0022 (")
    { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00 },   // U+0023 (#)
    { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00 },   // U+0024 ($)

const unsigned char font_table_13_col[96][13] = {
    // from URL https://courses.cs.washington.edu/courses/cse457/98a/tech/OpenGL/font.c
    //  GLubyte rasters[][13] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },/*" ",0*/
    { 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },/*"!",1*/
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36 },/*""",2*/
    { 0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00 },/*"#",3*/
    { 0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18 },/*"$",4*/

Преобразование растровых изображений шрифтов для правильного отображения

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

Код для рисования одной строки символа выглядит следующим образом. Схема этой функции заключается в предоставлении контроллеру ЖК-дисплея прямоугольника, определяющего область дисплея, которую нужно изменить, за которой следует серия из двух 8-битных записей для установки двухбайтового значения цвета RGB565 для каждого пикселя в области.

static bool TFTLCD::draw_glyph(unsigned short x0, unsigned short y0, TftColor fg_color, TftColor bg_color, unsigned char bitMap, unsigned char bmWidth, unsigned char flags)
{
    // we will fill a single row of 8 pixels by iterating over
    // a bitmap font map of which pixels to set to the foreground
    // color and which pixels to set to the background color for this
    // part of the character to display.

    // first determine whether we are scaling the default width by a multiplier
    // of 2 or 3 times the default size. this allows us to have different sizes
    // of text using the same bitmap font.
    if (flags & 0x01)
        set_area(x0, y0, x0 + bmWidth * 2 - 1, y0); // scale the default width to double wide
    else if (flags & 0x02)
        set_area(x0, y0, x0 + bmWidth * 3 - 1, y0); // scale the default width to tripple wide
    else
        set_area(x0, y0, x0 + bmWidth - 1, y0);    // default width and size with no scaling

    if (flags & 0x20) {    // Font::font_flags & FontTable::Flags_InvertBitOrder
        // inverting the order of painting the bits. means the bitmap of the
        // font would display the text with each character flipped if we did not do this.
        for (unsigned char char_n = 0x80; char_n; char_n >>= 1)
        {
            if (bitMap & char_n)
            {
                w_data(fg_color >> 8);
                w_data(fg_color);
            }
            else {
                w_data(bg_color >> 8);
                w_data(bg_color);
            }
            if (flags & 0x03) {         // double wide or triple wide
                if (bitMap & char_n)
                {
                    w_data(fg_color >> 8);
                    w_data(fg_color);
                }
                else {
                    w_data(bg_color >> 8);
                    w_data(bg_color);
                }
                if (flags & 0x02) {          // triple wide
                    if (bitMap & char_n)
                    {
                        w_data(fg_color >> 8);
                        w_data(fg_color);
                    }
                    else {
                        w_data(bg_color >> 8);
                        w_data(bg_color);
                    }
                }
            }
        }
    }
    else {
        for (unsigned char char_n = 1; char_n; char_n <<= 1)
        {
            if (bitMap & char_n)
            {
                w_data(fg_color >> 8);
                w_data(fg_color);
            }
            else {
                w_data(bg_color >> 8);
                w_data(bg_color);
            }
            if (flags & 0x03) {         // double wide or triple wide
                if (bitMap & char_n)
                {
                    w_data(fg_color >> 8);
                    w_data(fg_color);
                }
                else {
                    w_data(bg_color >> 8);
                    w_data(bg_color);
                }
                if (flags & 0x02) {          // triple wide
                    if (bitMap & char_n)
                    {
                        w_data(fg_color >> 8);
                        w_data(fg_color);
                    }
                    else {
                        w_data(bg_color >> 8);
                        w_data(bg_color);
                    }
                }
            }
        }
    }

    return 1;

и исходный код, который использует вышеуказанную функцию для рисования полных символов, выглядит следующим образом. Этот код использует функцию drawGlyph() для рисования серии фрагментов текстового символа сверху вниз. Время выполнения преобразования растрового изображения зависит от представления растрового изображения.

unsigned char glyphFlags = ((Font::font_flags & FontTable::Flags_DoubleWide) ? 1 : 0) | ((Font::font_flags & FontTable::Flags_TripleWide) ? 2 : 0);

if (Font::font_flags & FontTable::Flags_InvertBitOrder) {
    glyphFlags |= 0x20;
    for (signed char char_m = Font::font_table.nCols - 1; char_m >= 0; char_m--)
    {
        TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
        // shift down to the next row of pixels for the character
        Font::now_y++;
        if (font_flags & (FontTable::Flags_DoubleHigh | FontTable::Flags_TripleHigh)) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
        if (font_flags & FontTable::Flags_TripleHigh) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
    }
}
else if (Font::font_flags & FontTable::Flags_RotateBits) {
    for (unsigned char char_m = 0; char_m < 8; char_m++)
    {
        unsigned char rotatedMap = 0;
        for (unsigned char char_x = 0; char_x < Font::font_table.nCols; char_x++) {
            rotatedMap |= ((Font::font_table.table[char_i_x + char_x] & (1 << char_m)) ? 1 : 0) << char_x;
        }
        TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, rotatedMap, 8, glyphFlags);
        // shift down to the next row of pixels for the character
        Font::now_y++;
        if (font_flags & (FontTable::Flags_DoubleHigh | FontTable::Flags_TripleHigh)) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, rotatedMap, 8, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
        if (font_flags & FontTable::Flags_TripleHigh) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, rotatedMap, 8, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
    }
}
else {
    for (unsigned char char_m = 0; char_m < Font::font_table.nCols; char_m++)
    {
        TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
        // shift down to the next row of pixels for the character
        Font::now_y++;
        if (font_flags & (FontTable::Flags_DoubleHigh | FontTable::Flags_TripleHigh)) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
        if (font_flags & FontTable::Flags_TripleHigh) {
            TFTLCD::draw_glyph(Font::now_x, Font::now_y, Font::font_color, Font::txt_backcolor, Font::font_table.table[char_i_x + char_m], Font::font_table.nCols, glyphFlags);
            // shift down to the next row of pixels for the character
            Font::now_y++;
        }
    }
}

Характеристики растрового или растрового шрифта

Существует ряд спецификаций шрифтов, включая растровые шрифты растрового типа. Эти спецификации не обязательно описывают растровые изображения глифов, используемые в таких приложениях, как библиотека KeDei TFT, а скорее предоставляют независимое от устройства описание формата растрового шрифта.

Формат распространения растрового изображения глифа

BITMAP начинает растровое изображение для текущего глифа. За этой линией должна следовать одна линия на пиксель по оси Y. В этом примере глиф имеет высоту 16 пикселей, поэтому за ним следует 16 строк. Каждая строка содержит шестнадцатеричное представление пикселей в строке. 1 бит указывает визуализированный пиксель. Каждая строка округляется до 8-битной (один байт) границы, дополняется нулями справа. В этом примере глиф имеет ширину ровно 8 пикселей и поэтому занимает ровно 8 бит (один байт) на строку, поэтому отступы отсутствуют. Старший бит строки растровых данных представляет крайний левый пиксель.

Руководство разработчика Oracle в Solarix X Window System, глава 4 Поддержка шрифтов по адресу https://docs.oracle.com/cd/E19253-01/816-0279/6m6pd1cvk/index.html содержит таблицу, в которой перечислены несколько различных форматов растровых шрифтов, и говорит следующее:

Как показано в таблице 4–4, многие форматы файлов растровых шрифтов являются двоичными файлами, зависящими от архитектуры. Их нельзя использовать совместно между машинами с разной архитектурой (например, между SPARC и IA).

  • Формат распространения растрового изображения, файл .bdf, не двоичный, не зависящий от архитектуры
  • Портативный скомпилированный формат, файл .pcf, двоичный файл, не зависящий от архитектуры
  • Предустановленный формат Little Endian, двоичный, зависящий от архитектуры
  • Готовый формат Big Endian, двоичный, зависящий от архитектуры

PSF (экранный шрифт для ПК), двоичная спецификация, описанная по адресу https://www.win.tue.nl/%7Eaeb/linux/kbd/font-formats-1.html

PSF расшифровывается как экранный шрифт ПК. Формат psf1 без карты Unicode был разработан Х. Питером Анвином примерно в 1989 году для его редактора экранных шрифтов DOS FONTEDIT.EXE. В октябре 1994 года он добавил карту Unicode и программы psfaddtable, psfgettable, psfstriptable для управления ею — см. kbd-0.90. Андрис Брауэр добавил поддержку последовательностей значений Unicode и формата psf2 в сентябре 1999 г. для обработки тибетского языка — см. kbd-1.00.

Microsoft Q65123 из архива ранних статей базы знаний Microsoft https://jeffpar.github.io/kbarchive/kb/065/Q65123/

Форматы файлов шрифтов Microsoft Windows определены как для растровых, так и для векторных шрифтов. Эти форматы могут использоваться интеллектуальными генераторами текста в некоторых модулях поддержки GDI. В частности, векторные форматы чаще используются самим GDI, чем вспомогательными модулями.

Спецификация файла шрифта Metagraphics .fnt https://www.metagraphics.com/metawindow/fonts/fnt-specs.htm

Графическая библиотека Microchip, Шрифты AN1182 в графической библиотеке Microchip (PDF)

Смотрите также

Где я могу найти спецификацию формата .fon?

На этом веб-сайте File Formats есть описания нескольких различных спецификаций шрифтов. https://docs.fileformat.com/font/fnt/


person Richard Chambers    schedule 10.05.2021    source источник
comment
Вы действительно ожидаете, что кто-то прочитает это чудовище? Только ваш раздел «Мой вопрос» содержит около 7 отдельных вопросов.   -  person Piglet    schedule 10.05.2021
comment
@Piglet Да, я думаю, что кто-то ответит и, возможно, у кого-то будет ответ. На самом деле есть только один вопрос: каковы правила, стандарты или ожидаемые представления битовых данных для растровых шрифтов? Другие вопросы являются риторическими, чтобы лучше понять некоторые проблемы, связанные с фактическим вопросом. Центральное изображение, на котором сравниваются различные растровые изображения, иллюстрирует проблему, вызвавшую вопрос. Остальное — просто документация, показывающая код для (1) центрального генератора изображений и (2) моего решения проблемы, вызвавшей вопрос.   -  person Richard Chambers    schedule 10.05.2021
comment
@Piglet Я пошел на это, потому что видел разрозненные решения и хотел объединить некоторые из них в одном месте. Я надеюсь, что следующему человеку, работающему над этой проблемой, этот пост поможет увидеть, что я сделал, и, надеюсь, расширить его. Кажется, это то, что люди делают здесь. Моя следующая задача — просеять сообщения SO, чтобы найти других, у которых есть часть проблемы, с которой я столкнулся, и связать их вместе.   -  person Richard Chambers    schedule 10.05.2021
comment
@Piglet Я, например, освежен проницательностью и качеством вопросов, которые OP опубликовал в последнее время. Они глубоки и гораздо интереснее, чем типичный пример того, как подключить шаговый двигатель, или я скопировал этот код из Интернета, и он не работает не по теме, некоторые пользователи бездумно публикуют здесь.   -  person TomServo    schedule 11.05.2021
comment
@TomServo да, качество этого поста превосходное. Я просто хочу, чтобы это было немного короче. мой комментарий, наверное, прозвучал слишком резко. простите за это.   -  person Piglet    schedule 11.05.2021
comment
@RichardChambers Отмечу одну вещь: я уже создавал растровые шрифты для аналогичных целей. Большинство утилит, которые я использовал, берут какой-то шрифт, обычно TrueType, и некоторые характеристики, такие как высота и ширина (включая) нисходящие элементы, а затем растрируют в это пространство. В каждом случае вывод был в порядке строк, как вы показали выше ранее. Результаты, как правило, не очень хорошие, но растеризация очень маленького изображения TrueType обычно работала намного лучше, чем растеризация более крупного изображения, потому что многие артефакты уменьшались.   -  person TomServo    schedule 11.05.2021
comment
@TomServo В моем обзоре литературы по этой теме я видел что-то вроде того, что вы описываете. По-видимому, существует несколько утилит с открытым исходным кодом для растеризации не растровых шрифтов, таких как TrueType. Спасибо, что сообщили мне о своих результатах. Я взглянул на один с именем fontedit, который создает файл .fnt, однако есть шаг экспорта файла .fnt в виде таблицы растровых шрифтов в стиле C. Что вы использовали для генерации исходного кода C/C++, содержащего таблицу растровых шрифтов?   -  person Richard Chambers    schedule 11.05.2021
comment
Руководство программиста по картам EGA, VGA и Super VGA, третье издание «nofollow noreferrer»>archive.org/details/ на странице 170 (PDF, страница 194 из 1612) Буквенно-цифровая обработка, раздел 6.2.2 Представление символов в памяти. В разделе 6.2 есть несколько связанных разделов о представлении символов растровым шрифтом.   -  person Richard Chambers    schedule 13.05.2021
comment
Коллекция растровых изображений шрифтов из ПЗУ различных устройств, таких как IBM PC. github.com/viler-int10h/vga-text-mode-fonts большинство из них имеют одинаковый размер: 8 пикселей в ширину и 14 или 16 пикселей в высоту. Похоже, что они были сохранены по определенному смещению в ПЗУ с растровыми битовыми картами, представленными серией шестнадцатеричных цифр. Те, которые я рассматривал, используют один байт на строку текстового символа, поэтому для 8 на 16 требуется 16 байтов на символ. Растровые изображения хранятся в основном порядке строк, старший значащий бит находится слева от самого пикселя.   -  person Richard Chambers    schedule 13.05.2021
comment
Статья, описывающая извлечение шрифтов из ПЗУ видеокарты и их замену. Интересно увидеть некоторые из методов, таких как использование ртутной лампы для стирания стираемой УФ-излучением EPROM alexandrugroza.ro/microelectronics/essays-research/ и см. этот документ , руководство по контроллеру CRT archive.org/details/crt_controller_handbook/page/n13/mode/2up, а также раздел драйверов/видео на xml.com/ldd/chapter/book/ch16.html   -  person Richard Chambers    schedule 13.05.2021


Ответы (1)


Растровые или растровые шрифты представлены различными способами, и существуют стандарты файлов растровых шрифтов, разработанные как для Linux, так и для Windows. Однако представление необработанных данных растровых шрифтов в исходном коде языка программирования, по-видимому, зависит от:

  • архитектура памяти целевого компьютера,
  • архитектура и пути связи с контроллером дисплея,
  • символьный глиф высотой и шириной в пикселях и
  • объем памяти для хранения растровых изображений и какие меры принимаются, чтобы сделать его как можно меньше.

Краткий обзор растровых шрифтов

Общая растровая карта — это блок данных, в котором отдельные биты используются для указания состояния «включено» или «выключено». Одним из способов использования растрового изображения является хранение данных изображения. Глифы символов можно создавать и хранить в виде набора изображений, по одному для каждого символа в наборе символов, поэтому использование растрового изображения для кодирования и хранения изображения каждого символа является естественным подходом.

Растровые шрифты — это растровые изображения, используемые для указания того, как отображать или печатать символы, включая или отключая пиксели или печатая или не печатая точки на странице. См. раздел Растровые шрифты Википедии.

Растровый шрифт — это шрифт, в котором каждый глиф хранится в виде массива пикселей (т. е. растрового изображения). Он менее известен как растровый шрифт или пиксельный шрифт. Растровые шрифты — это просто наборы растровых изображений глифов. Для каждого варианта шрифта существует полный набор изображений глифов, причем каждый набор содержит изображение для каждого символа. Например, если шрифт имеет три размера и любое сочетание полужирного и курсивного начертаний, то должно быть 12 полных наборов изображений.

Краткая история использования растровых шрифтов

Первые терминалы с пользовательским интерфейсом, такие как телетайпные терминалы, использовали матричный принтер для печати на рулонах бумаги. С развитием терминалов с электронно-лучевой трубкой растровые шрифты можно было легко перенести на эту технологию в виде точек. люминесценция включается и выключается сканирующей электронной пушкой.

Самые ранние растровые шрифты имели фиксированную высоту и ширину, при этом растровое изображение действовало как своего рода штамп или шаблон для печати символов на выходном носителе, бумаге или трубке дисплея с фиксированной высотой строки и фиксированной шириной строки, такими как 80 столбцов и 24 строки терминала DEC VT-100.

С увеличением вычислительной мощности стал доступен более сложный типографский подход с использованием векторных шрифтов, используемых для улучшения качества отображаемого текста и обеспечения улучшенного масштабирования, а также для уменьшения памяти, необходимой для описания глифов символов.

Кроме того, в то время как матрица точек или пикселей работала довольно хорошо для таких языков, как английский, письменные языки со сложными формами глифов плохо обслуживались растровыми шрифтами.

Представление растровых шрифтов в исходном коде

Существует ряд форматов файлов растровых шрифтов, которые обеспечивают способ представления растрового шрифта в независимом от устройства описании. Пример см. в теме Википедии — Формат распространения растровых изображений Glyph.

Формат распространения растровых изображений Glyph (BDF) от Adobe — это формат файла для хранения растровых шрифтов. Содержимое имеет форму текстового файла, предназначенного для чтения человеком и компьютером. BDF обычно используется в средах Unix X Window. Он был в значительной степени заменен форматом шрифта PCF, который несколько более эффективен, и масштабируемыми шрифтами, такими как шрифты OpenType и TrueType.

Другие стандарты растровых изображений, такие как XBM, раздел Википедии — X BitMap или XPM, Тема Википедии — X PixMap — это компоненты исходного кода, описывающие растровые изображения, однако многие из них не предназначены специально для растровых шрифтов. а скорее другие графические изображения, такие как значки, курсоры и т. д.

Поскольку растровые шрифты являются более старым форматом, во многих случаях растровые шрифты заключаются в другой стандарт шрифтов, такой как TrueType, чтобы быть совместимыми со стандартными подсистемами шрифтов современных операционных систем, таких как Linux и Windows.

Однако встроенным системам, работающим на «голом железе» или использующим RTOS, обычно требуются необработанные данные изображения растровых символов в форме, аналогичной формату XBM. См. Энциклопедию форматов графических файлов, в которой есть этот пример:

Ниже приведен пример растрового изображения 16x16, сохраненного с использованием вариантов X10 и X11. Обратите внимание, что каждый массив содержит одни и те же данные, но хранится с использованием разных типов слов данных:

/* XBM X10 format */
#define xlogo16_width 16
#define xlogo16_height 16

static unsigned short xlogo16_bits[] = {
  0x0f80, 0x1e80, 0x3c40, 0x7820, 0x7810, 0xf008, 0xe009, 0xc005,
  0xc002, 0x4007, 0x200f, 0x201e, 0x101e, 0x083c, 0x0478, 0x02f0};

/* XBM X11 format */
#define xlogo16_width 16
#define xlogo16_height 16

static unsigned char xlogo16_bits[] = {
    0x0f, 0x80, 0x1e, 0x80, 0x3c, 0x40, 0x78, 0x20, 0x78, 0x10,
    0xf0, 0x08, 0xe0, 0x09, 0xc0, 0x05, 0xc0, 0x02, 0x40, 0x07,
    0x20, 0x0f, 0x20, 0x1e, 0x10, 0x1e, 0x08, 0x3c, 0x04, 0x78,
    0x02, 0xf0};

Порядок обхода битов каждой части данных в растровом шрифте важен для достижения желаемых результатов.

Поскольку размер каждого пикселя составляет всего один бит, каждый байт в массиве содержит информацию о восьми пикселях, при этом первый пиксель в растровом изображении (в позиции 0,0) представлен старшим битом первого байта в массиве. Если ширина изображения не кратна восьми, лишние биты в последнем байте каждой строки не используются и игнорируются.

Хотя это описание кажется достаточно хорошим, определение старшего бита первого байта зависит от архитектуры машины, Big -endian против Little-endian. На следующем изображении, построенном с использованием приведенного выше описания XBM логотипа X, слева показано перемещение битов каждого байта растровых данных на процессоре Intel i7-7900 от старшего бита к младшему биту, а справа — обратное.

Отображаемое изображение XBM 16x16. Сравнение байтов с обратным порядком байтов и обратным порядком байтов

Соображения относительно растровых шрифтов

Растровые шрифты имеют размер ячейки или высоту и ширину символа в пикселях или точках. Строка текста представляет собой серию этих ячеек, проставленных или нарисованных на дисплее, пиксель за пикселем.

Поскольку растровое изображение растрового шрифта не является независимым от устройства, поскольку представляет собой серию цифр, необработанные данные, описывающие изображение символа растрового шрифта, а также способ хранения этих данных в памяти и доступ к ним со стороны ЦП, зависят от устройства. Данные растрового изображения также могут быть преобразованы для более эффективного использования машинных ресурсов.

Растровые изображения растрового шрифта могут храниться таким образом, чтобы экономить используемую память, но при этом требовать дополнительной обработки для правильного размещения пикселей на поверхности рисования. Таким образом, шрифт размером 5 пикселей в ширину и 8 пикселей в высоту может быть сохранен сначала по высоте, а не по ширине, чтобы полностью использовать 8 бит беззнакового символа.

В дополнение к вращению растрового изображения для более эффективного использования битов в байте могут использоваться алгоритмы сжатия для уменьшения объема памяти, необходимого для таблицы растровых шрифтов. Обсуждение методов см. в разделе алгоритм упрощенного (де)сжатия для встроенного использования.

Архитектура машины может по-разному обращаться к отдельным битам, представляющим пиксели. Необработанные данные растрового шрифта, предназначенные для обработки на машине с прямым порядком байтов, будут отличаться от того, как эти необработанные данные будут представлены на машине с прямым порядком байтов. См. эту статью от IBM Написание независимого от порядка байтов кода на C.

Полезно иметь инструмент для визуализации растрового шрифта и обеспечения различных преобразований данных растрового шрифта для изучения того, какие изменения могут потребоваться для отображения растровых символов. Например, вот приложение Windows с графическим интерфейсом, которое я использовал для экспериментов с растровыми шрифтами, https://github.com/RichardChambers/utilities_tools/tree/main/fontshow

person Richard Chambers    schedule 28.05.2021
comment
Веб-страница jared.geek.nz/2014/jan/custom-fonts -for-microcontrollers имеет загружаемый ZIP-файл, содержащий различные шрифты, которые были преобразованы в необработанные данные в виде массивов C шестнадцатеричных цифр. - person Richard Chambers; 29.05.2021