u8g2原理解析

u8g2_font_info_t 结构体用于存储 U8g2 图形库中字体的相关信息.

1. 字符计数与编码模式相关信息(偏移量 0)

uint8_t glyph_cnt;
uint8_t bbx_mode;
uint8_t bits_per_0;
uint8_t bits_per_1;

glyph_cnt:
含义:表示字体中可用字符(字形,glyph)的数量。这有助于确定字体所能支持的字符范围。
用途:在遍历字体中的字符时,可根据此值来控制循环范围。
bbx_mode:
含义:边界框(bounding box)模式。边界框用于定义字符的最小矩形区域,此模式决定了如何计算和使用这些边界框。
用途:在进行字符布局和对齐时,根据不同的模式来确定字符的位置和大小。
bits_per_0 和 bits_per_1:
含义:分别表示编码中 “0” 和 “1” 所占用的位数。在字体的点阵数据编码中,不同的编码方式可能对 “0” 和 “1” 的表示位数有不同要求。
用途:在解码字体点阵数据时,根据这些位数信息来正确解析数据。

2. 字符尺寸编码位数信息(偏移量 4)

uint8_t bits_per_char_width;
uint8_t bits_per_char_height;
uint8_t bits_per_char_x;
uint8_t bits_per_char_y;
uint8_t bits_per_delta_x;
bits_per_char_width:

含义:表示字符宽度编码所占用的位数。
用途:在读取字体数据中字符宽度信息时,根据此位数进行解析。
bits_per_char_height:
含义:表示字符高度编码所占用的位数。
用途:同理,用于解析字符高度信息。
bits_per_char_x 和 bits_per_char_y:
含义:分别表示字符在 X 轴和 Y 轴上位置编码所占用的位数。
用途:用于确定字符在字体中的具体位置。
bits_per_delta_x:
含义:表示字符在 X 轴上的偏移量编码所占用的位数。
用途:在进行字符布局时,根据此偏移量来调整字符之间的间距。

3. 字符最大尺寸与偏移信息(偏移量 9)

int8_t max_char_width;
int8_t max_char_height; 
int8_t x_offset;
int8_t y_offset;
max_char_width:

含义:字体中字符的最大宽度。
用途:在进行文本布局时,可根据此值来估算一行文本所需的最大宽度。
max_char_height:
含义:字体中字符的最大高度,注意这里是整体高度,而不是上升高度(ascent)。上升高度等于 max_char_height + y_offset。
用途:用于确定文本行的高度。
x_offset 和 y_offset:
含义:分别表示字符在 X 轴和 Y 轴上的偏移量。
用途:在绘制字符时,根据这些偏移量来调整字符的位置。

4. 字符上升和下降高度信息(偏移量 13)

int8_t  ascent_A;
int8_t  descent_g;
int8_t  ascent_para;
int8_t  descent_para;

ascent_A:
含义:大写字母 “A” 的上升高度,即字符从基线(baseline)到最高点的距离。
用途:在文本布局中,用于确定文本行的顶部位置。
descent_g:
含义:小写字母 “g” 的下降高度,通常为负值,表示字符从基线到最低点的距离。
用途:用于确定文本行的底部位置。
ascent_para 和 descent_para:
含义:分别表示段落的上升高度和下降高度,可能用于处理多行文本的布局。
用途:在进行段落排版时,根据这些值来调整行间距和段落的整体布局。

5. 字符起始位置信息(偏移量 17)

uint16_t start_pos_upper_A;
uint16_t start_pos_lower_a; 
start_pos_upper_A:

含义:大写字母 “A” 在字体数据中的起始位置。
用途:在查找大写字母 “A” 的点阵数据时,根据此位置进行定位。
start_pos_lower_a:
含义:小写字母 “a” 在字体数据中的起始位置。
用途:同理,用于查找小写字母 “a” 的点阵数据。

6. Unicode 字符起始位置信息(偏移量 21,可选)

#ifdef U8G2_WITH_UNICODE  
uint16_t start_pos_unicode;
#endif

start_pos_unicode:
含义:如果启用了 Unicode 支持(U8G2_WITH_UNICODE 宏定义),此成员表示 Unicode 字符在字体数据中的起始位置。
用途:在处理 Unicode 字符时,根据此位置来查找相应的点阵数据。
综上所述,u8g2_font_info_t 结构体通过存储字体的各种信息,为 U8g2 库在文本渲染和布局过程中提供了必要的参数,确保能够正确地显示和排版文本。

u8g2_draw_string

函数定义和参数

static u8g2_uint_t u8g2_draw_string(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)

static:表示该函数是一个静态函数,其作用域仅限于当前文件。
返回值:u8g2_uint_t 类型,返回绘制整个字符串所占用的水平或垂直总长度(根据字体旋转方向而定)。
参数:
u8g2_t *u8g2:指向 u8g2_t 结构体的指针,该结构体包含了 U8g2 库的上下文信息,如显示屏设置、字体信息等。
u8g2_uint_t x 和 u8g2_uint_t y:指定字符串绘制的起始坐标。
const char *str:指向要绘制的字符串的指针。
变量声明

uint16_t e;
u8g2_uint_t delta, sum;

e:用于存储从字符串中解码出的 Unicode 字符编码。
delta:表示绘制单个字符所占用的水平或垂直长度。
sum:用于累加绘制整个字符串所占用的总长度。
UTF - 8 初始化

u8x8_utf8_init(u8g2_GetU8x8(u8g2));

调用 u8x8_utf8_init 函数对 UTF - 8 解码进行初始化,确保后续能正确处理 UTF - 8 编码的字符串。u8g2_GetU8x8(u8g2) 用于获取 u8g2 结构体中关联的 u8x8 上下文。
初始化总长度

sum = 0;

将 sum 初始化为 0,用于后续累加字符绘制的长度。
字符串处理循环

for(;;)
{
    e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
    if ( e == 0x0ffff )
        break;
    str++;

u8g2->u8x8.next_cb 是一个回调函数,用于从字符串中解码出下一个 Unicode 字符编码。
如果解码结果为 0x0ffff,表示已经到达字符串的末尾,此时跳出循环。
每次解码后,将字符串指针 str 向后移动一位。
绘制字符

if ( e != 0x0fffe )
{
    delta = u8g2_DrawGlyph(u8g2, x, y, e);

如果解码结果不是 0x0fffe(表示无效字符),则调用 u8g2_DrawGlyph 函数在指定位置 (x, y) 绘制该 Unicode 字符。该函数返回绘制该字符所占用的水平或垂直长度,存储在 delta 中。
处理字体旋转

#ifdef U8G2_WITH_FONT_ROTATION
    switch(u8g2->font_decode.dir)
    {
        case 0:
            x += delta;
            break;
        case 1:
            y += delta;
            break;
        case 2:
            x -= delta;
            break;
        case 3:
            y -= delta;
            break;
    }

    /*
    // requires 10 bytes more on avr
    x = u8g2_add_vector_x(x, delta, 0, u8g2->font_decode.dir);
    y = u8g2_add_vector_y(y, delta, 0, u8g2->font_decode.dir);
    */

#else
    x += delta;
#endif

启用字体旋转支持(U8G2_WITH_FONT_ROTATION 宏定义):
根据 u8g2->font_decode.dir 的值(表示字体旋转方向),更新下一个字符的绘制位置。
case 0:正常水平方向,x 坐标增加 delta。
case 1:顺时针旋转 90 度,y 坐标增加 delta。
case 2:顺时针旋转 180 度,x 坐标减少 delta。
case 3:顺时针旋转 270 度,y 坐标减少 delta。
注释掉的代码 u8g2_add_vector_x 和 u8g2_add_vector_y 是另一种实现方式,但会增加 AVR 平台的代码大小。
未启用字体旋转支持:默认情况下,水平方向绘制,x 坐标增加 delta。
累加总长度

sum += delta;    

将当前字符绘制所占用的长度 delta 累加到 sum 中。
返回总长度

return sum;

循环结束后,返回绘制整个字符串所占用的总长度。

UFT8解码函数(将中文变成UFT8解码)

uint16_t u8x8_utf8_next(u8x8_t *u8x8, uint8_t b)
{
  if ( b == 0 || b == '\n' )	/* '\n' terminates the string to support the string list procedures */
    return 0x0ffff;	/* end of string detected, pending UTF8 is discarded */
  if ( u8x8->utf8_state == 0 )
  {
    if ( b >= 0xfc )	/* 6 byte sequence */
    {
      u8x8->utf8_state = 5;
      b &= 1;
    }
    else if ( b >= 0xf8 )
    {
      u8x8->utf8_state = 4;
      b &= 3;
    }
    else if ( b >= 0xf0 )
    {
      u8x8->utf8_state = 3;
      b &= 7;      
    }
    else if ( b >= 0xe0 )
    {
      u8x8->utf8_state = 2;
      b &= 15;
    }
    else if ( b >= 0xc0 )
    {
      u8x8->utf8_state = 1;
      b &= 0x01f;
    }
    else
    {
      /* do nothing, just use the value as encoding */
      return b;
    }
    u8x8->encoding = b;
    return 0x0fffe;
  }
  else
  { 
    u8x8->utf8_state--;
    /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
    u8x8->encoding<<=6;
    b &= 0x03f;
    u8x8->encoding |= b;
    if ( u8x8->utf8_state != 0 )
      return 0x0fffe;	/* nothing to do yet */
  }
  return u8x8->encoding;
}

一个例子**“世界” 的 Unicode 编码及解析过程**

  1. Unicode 编码结果
    世:U+4E16
    界:U+754C
  2. UTF-8 编码解析过程
    根据 UTF-8 编码规则,将 Unicode 代码点转换为字节序列的步骤如下:
    “世”(U+4E16)的编码
    代码点转换为二进制
    U+4E16 → 二进制 0100 1110 0001 0110。
    按三字节格式拆分
    UTF-8 三字节格式为:
    plaintext
    1110xxxx 10xxxxyy 10yyyyyy

将二进制位分配到各字段:
第一部分(4 位):0100
第二部分(6 位):111000
第三部分(6 位):010110
生成字节序列
第一字节:1110 0100 → 0xE4
第二字节:10 111000 → 0xB8
第三字节:10 010110 → 0x96

最终 UTF-8 编码:E4 B8 96。
“界”(U+754C)的编码
代码点转换为二进制
U+754C → 二进制 0111 0101 0100 1100。
按三字节格式拆分
第一部分(4 位):0111
第二部分(6 位):010101
第三部分(6 位):001100
生成字节序列
第一字节:1110 0111 → 0xE7
第二字节:10 010101 → 0x95
第三字节:10 001100 → 0x8C

最终 UTF-8 编码:E7 95 8C。
3. 结合u8x8_utf8_next函数的处理逻辑
当函数依次处理 “世界” 的 UTF-8 字节E4 B8 96 E7 95 8C时:
处理E4(0xE4)
b = 0xE4,判断为三字节序列(0xE0 ≤ b < 0xF0)。
utf8_state设为 2,encoding保存0x16(E4的低 4 位),返回0x0fffe。
处理B8(0xB8)
utf8_state减为 1,encoding左移 6 位,合并B8的低 6 位(0x18)。
encoding = 0x16 << 6 | 0x18 = 0x1618,返回0x0fffe。
处理96(0x96)
utf8_state减为 0,encoding左移 6 位,合并96的低 6 位(0x16)。
encoding = 0x1618 << 6 | 0x16 = 0x4E16,返回0x4E16(“世” 的 Unicode 编码)。
处理E7(0xE7)
重复上述步骤,最终返回0x754C(“界” 的 Unicode 编码)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值