UP 字库生成脚本

main
JiXieShi 2024-06-24 22:58:18 +08:00
parent 790d26fbaa
commit dd27c265da
10 changed files with 929 additions and 32 deletions

View File

@ -23,4 +23,6 @@ add_executable(HW_Lib main.c ${SOURCES})
#
add_subdirectory(lib)
target_link_libraries(HW_Lib HW_LIB_List HW_LIB_Task HW_LIB_Printf HW_LIB_Utils HW_LIB_Iic HW_LIB_Spi HW_LIB_Key HW_LIB_Oled)
target_link_libraries(HW_Lib HW_LIB_List HW_LIB_Task HW_LIB_Printf HW_LIB_Utils HW_LIB_Iic
HW_LIB_Spi HW_LIB_Key HW_LIB_Oled HW_LIB_Font
)

View File

@ -114,7 +114,7 @@ void Test_OLED() {
int s = 0;
char buf[30] = {0x5B, 0x57, 0x5E, 0x93, 0x75, 0x1F, 0x62, 0x10, 0x6D, 0x4B, 0x8B, 0xD5};
OLED_ShowCHString(&oled, 15, 16, buf, 16);
OLED_ShowCHString(&oled, 15, 16, buf);
OLED_Refresh(&oled);
_beginthread(Get_Key, 0, NULL);

View File

@ -8,6 +8,7 @@ set(LIBRARIES
HW_LIB_Spi src/spi inc/spi
HW_LIB_Key src/key inc/key
HW_LIB_Oled src/oled inc/oled
HW_LIB_Font src/font inc/font
)
#

224
lib/inc/font/lvgl.h Normal file
View File

@ -0,0 +1,224 @@
#pragma once
#ifndef __lvgl_H
#define __lvgl_H
#include "stdlib.h"
#include "string.h"
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
/* Attribute to mark large constant arrays for example
* font's bitmaps */
#define LV_ATTRIBUTE_LARGE_CONST
/** Format of font character map. */
enum {
LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL,
LV_FONT_FMT_TXT_CMAP_SPARSE_TINY,
LV_FONT_FMT_TXT_CMAP_SPARSE_FULL,
};
typedef uint8_t lv_font_fmt_txt_cmap_type_t;
typedef uint8_t lv_opa_t;
/** This describes a glyph. */
typedef struct {
#if LV_FONT_FMT_TXT_LARGE == 0
uint32_t bitmap_index: 20; /**< Start index of the bitmap. A font can be max 1 MB. */
uint32_t adv_w: 12; /**< Draw the next glyph after this width. 8.4 format (real_value * 16 is stored). */
uint8_t box_w; /**< Width of the glyph's bounding box*/
uint8_t box_h; /**< Height of the glyph's bounding box*/
int8_t ofs_x; /**< x offset of the bounding box*/
int8_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/
#else
uint32_t bitmap_index; /**< Start index of the bitmap. A font can be max 4 GB. */
uint32_t adv_w; /**< Draw the next glyph after this width. 28.4 format (real_value * 16 is stored). */
uint16_t box_w; /**< Width of the glyph's bounding box*/
uint16_t box_h; /**< Height of the glyph's bounding box*/
int16_t ofs_x; /**< x offset of the bounding box*/
int16_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/
#endif
} lv_font_fmt_txt_glyph_dsc_t;
/* 将码点映射到 `glyph_dsc` 的结构体
* 使
* https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md
*/
typedef struct {
/** 此范围的第一个Unicode字符 */
uint32_t range_start;
/** 与此范围相关的Unicode字符数。
* Unicode = range_start + range_length - 1*/
uint16_t range_length;
/** 此范围的第一个字形ID`glyph_dsc` 的数组索引) */
uint16_t glyph_id_start;
/*
4
https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md
rcp = codepoint - range_start
0
unicode_list == NULL && glyph_id_ofs_list == NULL
glyph_id = glyph_id_start + rcp
0
unicode_list == NULL && glyph_id_ofs_list != NULL
glyph_id = glyph_id_start + glyph_id_ofs_list[rcp]
Fomat
unicode_list != NULL && glyph_id_ofs_list == NULL
glyph_id = glyph_id_start + search(unicode_list, rcp)
Fomat
unicode_list != NULL && glyph_id_ofs_list != NULL
glyph_id = glyph_id_start + glyph_id_ofs_list[search(unicode_list, rcp)]
*/
const uint16_t *unicode_list;
/** 如果(type == LV_FONT_FMT_TXT_CMAP_FORMAT0_...),则为 `uint8_t *`
* (type == LV_FONT_FMT_TXT_CMAP_SPARSE_...) `uint16_t *`
*/
const void *glyph_id_ofs_list;
/** `unicode_list` 和/或 `glyph_id_ofs_list` 的长度 */
uint16_t list_length;
/** 此字符映射的类型 */
lv_font_fmt_txt_cmap_type_t type;
} lv_font_fmt_txt_cmap_t;
/* 描述字体的附加数据的结构体 */
typedef struct {
/* 所有字形的位图 */
const uint8_t *glyph_bitmap;
/* 描述字形 */
const lv_font_fmt_txt_glyph_dsc_t *glyph_dsc;
/* 将字形映射到Unicode字符。
* `lv_font_cmap_fmt_txt_t` */
const lv_font_fmt_txt_cmap_t *cmaps;
/* 存储字距值。
* `lv_font_fmt_txt_kern_pair_t *` `lv_font_kern_classes_fmt_txt_t *`
* `kern_classes` */
const void *kern_dsc;
/* 缩放字距值12.4格式 */
uint16_t kern_scale;
/* cmap表的数量 */
uint16_t cmap_num: 10;
/* 每像素位数1, 2, 3, 4, 8 */
uint16_t bpp: 4;
/* `kern_dsc` 的类型 */
uint16_t kern_classes: 1;
/*
*
* `lv_font_fmt_txt_bitmap_format_t`
*/
uint16_t bitmap_format: 2;
/* 缓存最后一个字母和其字形ID */
uint32_t last_letter;
uint32_t last_glyph_id;
} lv_font_fmt_txt_dsc_t;
/* 坐标类型。应为 `int16_t`(或在极端情况下为 `int32_t` */
typedef int16_t lv_coord_t;
/** 描述字形属性的结构体 */
typedef struct {
uint16_t adv_w; /**< 字形所需的空间。在此宽度后绘制下一个字形。8位整数4位小数 */
uint16_t box_w; /**< 字形的包围框宽度 */
uint16_t box_h; /**< 字形的包围框高度 */
int16_t ofs_x; /**< 包围框的x偏移量 */
int16_t ofs_y; /**< 包围框的y偏移量 */
uint8_t bpp; /**< 每像素位数1, 2, 4, 8 */
} lv_font_glyph_dsc_t;
/** 描述字体的属性的结构体 */
typedef struct _lv_font_struct {
/** 从字体中获取字形描述符 */
bool (*get_glyph_dsc)(const struct _lv_font_struct *, lv_font_glyph_dsc_t *, uint32_t letter, uint32_t letter_next);
/** 从字体中获取字形的位图 */
const uint8_t *(*get_glyph_bitmap)(const struct _lv_font_struct *, uint32_t);
/* 指向字体包中的字体的指针(必须具有相同的行高) */
lv_coord_t line_height; /**< 任何文本都适合的实际行高 */
lv_coord_t base_line; /**< 从行高顶部测量的基准线 */
uint8_t subpx: 2; /**< `lv_font_subpx_t` 的一个元素 */
int8_t underline_position; /**< 下划线顶部与基准线之间的距离(< 0 表示在基准线下方)*/
int8_t underline_thickness; /**< 下划线的厚度 */
void *dsc; /**< 在这里存储特定于实现或运行时数据或缓存 */
} lv_font_t;
#define NULL 0 /* see <stddef.h> */
/** Bitmap formats*/
typedef enum {
LV_FONT_FMT_TXT_PLAIN = 0,
LV_FONT_FMT_TXT_COMPRESSED = 1,
LV_FONT_FMT_TXT_COMPRESSED_NO_PREFILTER = 1,
} lv_font_fmt_txt_bitmap_format_t;
typedef uintptr_t lv_uintptr_t;
/** 用于简单映射字距值对的结构体 */
typedef struct {
/* 获取两个字符代码点之间的字距值:
1. `lv_font_fmt_txt_cmap_t` `glyph_id_left` `glyph_id_right`
2. for(i = 0; i < pair_cnt * 2; i+2)
if(gylph_ids[i] == glyph_id_left &&
gylph_ids[i+1] == glyph_id_right)
return values[i / 2];
*/
const void *glyph_ids; /* 存储字形ID对 */
const int8_t *values; /* 存储字距值 */
uint32_t pair_cnt: 24; /* 字距值对的数量 */
uint32_t glyph_ids_size: 2; /* 0: `glyph_ids` 存储为 `uint8_t`; 1: 存储为 `uint16_t` */
} lv_font_fmt_txt_kern_pair_t;
/** 更复杂但更优化的基于类别的字距值存储结构体 */
typedef struct {
/* 结构体用于获取两个字符代码点之间的字距值:
1. `lv_font_fmt_txt_cmap_t` `glyph_id_left` `glyph_id_right`
2. `left_class` `right_class`
left_class = left_class_mapping[glyph_id_left];
right_class = right_class_mapping[glyph_id_right];
3. value = class_pair_values[(left_class-1)*right_class_cnt + (right_class-1)]
*/
const int8_t *class_pair_values; /* 存储左侧类别数 * 右侧类别数的值 */
const uint8_t *left_class_mapping; /* 将字形ID映射到类别索引 -> 字形ID -> 类别ID */
const uint8_t *right_class_mapping; /* 将字形ID映射到类别索引 -> 字形ID -> 类别ID */
uint8_t left_class_cnt; /* 左侧类别数 */
uint8_t right_class_cnt; /* 右侧类别数 */
} lv_font_fmt_txt_kern_classes_t;
#endif

20
lib/inc/font/lvgl_font.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#ifndef __lvgl_font_H
#define __lvgl_font_H
#include "stdlib.h"
#include "string.h"
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "lvgl.h"
#define LV_ANTIALIAS 0 //抗锯齿
char utf8_to_unicode(uint8_t *pInput, uint32_t *unicode_letter);
char lv_draw_letter(const lv_font_t *font, uint32_t letter, int16_t pos_x, int16_t pos_y);
#endif

View File

@ -1,3 +1,4 @@
#pragma once
#ifndef HW_LIB_OLED_H
#define HW_LIB_OLED_H
#ifdef __cplusplus
@ -219,11 +220,10 @@ void OLED_ShowString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *chr, uint8_t si
* @param x: [] X
* @param y: [] Y
* @param str: []
* @param size: []
* @return void
* @example OLED_ShowCHString(&oled_device, 0, 0, chinese_str, 16);
**/
void OLED_ShowCHString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *str, uint8_t size);
void OLED_ShowCHString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *str);
/**
* @brief OLED

View File

@ -1,46 +1,74 @@
#pragma once
#ifndef HW_LIB_OLED_FONT_CHUC_H
#define HW_LIB_OLED_FONT_CHUC_H
typedef struct {
uint8_t name[3];
uint8_t unicode[2];
uint8_t data[32];
} Chinese_t;
uint8_t Hzk_size = 16;
Chinese_t Hzk[] = {
{
// Original: 字
{0x5B, 0x57},
{0x10, 0x0C, 0x04, 0x24, 0x24, 0x24, 0x25, 0x26, 0xA4, 0x64, 0x24, 0x04, 0x04, 0x14, 0x0C, 0x00,
0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x82, 0x7F, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00
}},
{
0x10, 0x0C, 0x04, 0x24, 0x24, 0x24, 0x25, 0x26, 0xA4, 0x64, 0x24, 0x04, 0x04, 0x14, 0x0C, 0x00,
0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x82, 0x7F, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00,
}
},
{
// Original: 库
{0x5E, 0x93},
{0x00, 0x00, 0xFC, 0x24, 0x24, 0xA4, 0x64, 0x3D, 0xA6, 0x24, 0x24, 0x24, 0x24, 0x24, 0x04, 0x00,
0x40, 0x30, 0x0F, 0x10, 0x13, 0x12, 0x12, 0x12, 0xFF, 0x12, 0x12, 0x12, 0x12, 0x10, 0x10, 0x00
}},
{
0x00, 0x00, 0xFC, 0x24, 0x24, 0xA4, 0x64, 0x3D, 0xA6, 0x24, 0x24, 0x24, 0x24, 0x24, 0x04, 0x00,
0x40, 0x30, 0x0F, 0x10, 0x13, 0x12, 0x12, 0x12, 0xFF, 0x12, 0x12, 0x12, 0x12, 0x10, 0x10, 0x00,
}
},
{
// Original: 生
{0x75, 0x1F},
{0x80, 0x40, 0x30, 0x1E, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
0x40, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7F, 0x42, 0x42, 0x42, 0x42, 0x42, 0x40, 0x40, 0x00
}},
{
0x80, 0x40, 0x30, 0x1E, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
0x40, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7F, 0x42, 0x42, 0x42, 0x42, 0x42, 0x40, 0x40, 0x00,
}
},
{
// Original: 成
{0x62, 0x10},
{0x00, 0x00, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x08, 0x08, 0xFF, 0x08, 0x09, 0x0A, 0xC8, 0x08, 0x00,
0x80, 0x60, 0x1F, 0x00, 0x10, 0x20, 0x1F, 0x80, 0x40, 0x21, 0x16, 0x18, 0x26, 0x41, 0xF8, 0x00
}},
{
0x00, 0x00, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x08, 0x08, 0xFF, 0x08, 0x09, 0x0A, 0xC8, 0x08, 0x00,
0x80, 0x60, 0x1F, 0x00, 0x10, 0x20, 0x1F, 0x80, 0x40, 0x21, 0x16, 0x18, 0x26, 0x41, 0xF8, 0x00,
}
},
{
// Original: 测
{0x6D, 0x4B},
{0x10, 0x60, 0x02, 0x8C, 0x00, 0xFE, 0x02, 0xF2, 0x02, 0xFE, 0x00, 0xF8, 0x00, 0xFF, 0x00, 0x00,
0x04, 0x04, 0x7E, 0x01, 0x80, 0x47, 0x30, 0x0F, 0x10, 0x27, 0x00, 0x47, 0x80, 0x7F, 0x00, 0x00
}},
{
0x10, 0x60, 0x02, 0x8C, 0x00, 0xFE, 0x02, 0xF2, 0x02, 0xFE, 0x00, 0xF8, 0x00, 0xFF, 0x00, 0x00,
0x04, 0x04, 0x7E, 0x01, 0x80, 0x47, 0x30, 0x0F, 0x10, 0x27, 0x00, 0x47, 0x80, 0x7F, 0x00, 0x00,
}
},
{
// Original: 试
{0x8B, 0xD5},
{0x40, 0x40, 0x42, 0xCC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0x10, 0x11, 0x16, 0x10, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x10, 0x28, 0x60, 0x3F, 0x10, 0x10, 0x01, 0x0E, 0x30, 0x40, 0xF0, 0x00
}},
{
0x40, 0x40, 0x42, 0xCC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0x10, 0x11, 0x16, 0x10, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x10, 0x28, 0x60, 0x3F, 0x10, 0x10, 0x01, 0x0E, 0x30, 0x40, 0xF0, 0x00,
}
},
};
Chinese_t *find_chinese_data(uint8_t unicode_high, uint8_t unicode_low) {
for (int i = 0; i < sizeof(Hzk) / sizeof(Chinese_t); ++i) {
if (Hzk[i].unicode[0] == unicode_high && Hzk[i].unicode[1] == unicode_low) {
return &Hzk[i];
}
}
return NULL;
}
#endif //HW_LIB_OLED_FONT_CHUC_H

558
lib/src/font/lvgl_font.c Normal file
View File

@ -0,0 +1,558 @@
#include "lvgl.h"
#include "lvgl_font.h"
#define LV_HOR_RES_MAX 128
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show utf8_to_unicode
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
char utf8_to_unicode(uint8_t *pInput, uint32_t *unicode_letter) {
char outputSize = 0;
char ppOutput[8] = {0};
char *tmp = ppOutput; //临时变量,用于遍历输出字符串
if (*pInput > 0x00 && *pInput <= 0x7F) //处理单字节UTF8字符英文字母、数字
{
*tmp = *pInput;
tmp++;
*tmp = 0; //小端法表示在高地址填补0
outputSize = 1;
} else if (((*pInput) & 0xE0) == 0xC0) //处理双字节UTF8字符
{
char high = *pInput;
pInput++;
char low = *pInput;
if ((low & 0xC0) != 0x80) //检查是否为合法的UTF8字符表示
return 0; //如果不是则报错
*tmp = (high << 6) + (low & 0x3F);
tmp++;
*tmp = (high >> 2) & 0x07;
outputSize = 2;
} else if (((*pInput) & 0xF0) == 0xE0) //处理三字节UTF8字符
{
char high = *pInput;
pInput++;
char middle = *pInput;
pInput++;
char low = *pInput;
if (((middle & 0xC0) != 0x80) || ((low & 0xC0) != 0x80))
return 0;
*tmp = (middle << 6) + (low & 0x7F);
tmp++;
*tmp = (high << 4) + ((middle >> 2) & 0x0F);
outputSize = 3;
} else //对于其他字节数的UTF8字符不进行处理
{
return 0;
}
unicode_letter[0] = ppOutput[1];
unicode_letter[0] <<= 8;
unicode_letter[0] |= ppOutput[0];
return outputSize;
}
void
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show draw_letter_normal
// lv_opa_t opa ; //透明度 0-255
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void draw_letter_normal(uint16_t pos_x, uint16_t pos_y, lv_font_glyph_dsc_t *g, const uint8_t *map_p) {
uint32_t bitmask_init;
uint32_t bitmask;
uint32_t bpp = g->bpp;
if (bpp == 3)
bpp = 4;
switch (bpp) {
case 1:
bitmask_init = 0x80;
break;
case 2:
bitmask_init = 0xC0;
break;
case 4:
bitmask_init = 0xF0;
break;
case 8:
bitmask_init = 0xFF;
break;
default:
return; /*Invalid bpp. Can't render the letter*/
}
int32_t col, row;
int32_t box_w = g->box_w;
int32_t box_h = g->box_h;
int32_t width_bit = box_w * bpp; /*Letter width in bits*/
/* Calculate the col/row start/end on the map*/
int32_t col_start = 0;
int32_t col_end = box_w;
int32_t row_start = 0;
int32_t row_end = box_h;
/*Move on the map too*/
uint32_t bit_ofs = (row_start * width_bit) + (col_start * bpp);
map_p += bit_ofs >> 3;
uint8_t letter_px;
uint32_t col_bit;
col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */
// uint32_t mask_buf_size = box_w * box_h > LV_HOR_RES_MAX ? LV_HOR_RES_MAX : box_w * box_h;
// unsigned short mask_buf[LV_HOR_RES_MAX / 2];
uint8_t fbuf[128 / 8];
int32_t mask_p = 0;
uint32_t col_bit_max = 8 - bpp;
uint32_t col_bit_row_ofs = (box_w + col_start - col_end) * bpp;
uint8_t index = 0;
for (row = row_start; row < row_end; row++) {
int32_t mask_p_start = mask_p;
bitmask = bitmask_init >> col_bit;
for (col = col_start; col < col_end; col++) {
/*Load the pixel's opacity into the mask*/
letter_px = (*map_p & bitmask) >> (col_bit_max - col_bit);
// if (letter_px) 1;
// else 0;
if (letter_px) {
fbuf[index / 8] |= (1 << (index % 8));
} else {
fbuf[index / 8] &= ~(1 << (index % 8));
}
index++;
/*Go to the next column*/
if (col_bit < col_bit_max) {
col_bit += bpp;
bitmask >>= bpp;
} else {
col_bit = 0;
bitmask = bitmask_init;
map_p++;
}
/*Next mask byte*/
mask_p++;
}
{
// LCD_fill_fast(pos_x, pos_y, box_w, 1, (uint8_t *)mask_buf, box_w);
//// 读取fbuf的当前位置的二进制位
//bool read_bit = (fbuf[pos / 8] >> (pos % 8)) & 1;
pos_y++;
mask_p = 0;
} //避免大字体,大缓存 ,单行即刻刷入
col_bit += col_bit_row_ofs;
map_p += (col_bit >> 3);
col_bit = col_bit & 0x7;
}
// LCD_fill_fast(pos_x, pos_y, box_w, box_h, (uint8_t *)mask_buf, box_w * box_h); // 如果 大缓存 一次刷入
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show lv_draw_letter
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
char lv_draw_letter(const lv_font_t *font, uint32_t letter, int16_t pos_x, int16_t pos_y) {
const uint8_t *map_p;
lv_font_glyph_dsc_t g;
if (!font->get_glyph_dsc(font, &g, letter, '\0')) //获取字体 信息
return 0;
if (letter == ' ') // lvgl 空格没有实际数据 直接跳过
return g.box_w;
/* Don't draw anything if the character is empty. E.g. space */
if ((g.box_h == 0) || (g.box_w == 0))
return 0;
map_p = font->get_glyph_bitmap(font, letter); //获取字体 实际数据
if (map_p == NULL)
return 0;
pos_x += g.ofs_x; //偏移修正
pos_y += font->line_height - g.box_h - g.ofs_y;
if (pos_x < 1) //有的时候会为负
pos_x = 1;
if (pos_y < 1) //有的时候会为负
pos_y = 1;
draw_letter_normal(pos_x, pos_y, &g, map_p);
return g.box_w;
}
#if LV_FONT_UNSCII_8
/** Searches base[0] to base[n - 1] for an item that matches *key.
*
* @note The function cmp must return negative if its first
* argument (the search key) is less that its second (a table entry),
* zero if equal, and positive if greater.
*
* @note Items in the array must be in ascending order.
*
* @param key Pointer to item being searched for
* @param base Pointer to first element to search
* @param n Number of elements
* @param size Size of each element
* @param cmp Pointer to comparison function (see #lv_font_codeCompare as a comparison function
* example)
*
* @return a pointer to a matching item, or NULL if none exists.
*/
void *_lv_utils_bsearch(const void *key, const void *base, uint32_t n, uint32_t size,
int32_t (*cmp)(const void *pRef, const void *pElement))
{
const char *middle;
int32_t c;
for (middle = base; n != 0;)
{
middle += (n / 2) * size;
if ((c = (*cmp)(key, middle)) > 0)
{
n = (n / 2) - ((n & 1) == 0);
base = (middle += size);
}
else if (c < 0)
{
n /= 2;
middle = base;
}
else
{
return (char *)middle;
}
}
return NULL;
}
/** Code Comparator.
*
* Compares the value of both input arguments.
*
* @param[in] pRef Pointer to the reference.
* @param[in] pElement Pointer to the element to compare.
*
* @return Result of comparison.
* @retval < 0 Reference is greater than element.
* @retval = 0 Reference is equal to element.
* @retval > 0 Reference is less than element.
*
*/
static int32_t unicode_list_compare(const void *ref, const void *element)
{
return ((int32_t)(*(uint16_t *)ref)) - ((int32_t)(*(uint16_t *)element));
}
/**********************
* STATIC FUNCTIONS
**********************/
static uint32_t get_glyph_dsc_id(const lv_font_t *font, uint32_t letter)
{
if (letter == '\0')
return 0;
lv_font_fmt_txt_dsc_t *fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
/*Check the cache first*/
if (letter == fdsc->last_letter)
return fdsc->last_glyph_id;
uint16_t i;
for (i = 0; i < fdsc->cmap_num; i++)
{
/*Relative code point*/
uint32_t rcp = letter - fdsc->cmaps[i].range_start;
if (rcp > fdsc->cmaps[i].range_length)
continue;
uint32_t glyph_id = 0;
if (fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY)
{
glyph_id = fdsc->cmaps[i].glyph_id_start + rcp;
}
else if (fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL)
{
const uint8_t *gid_ofs_8 = fdsc->cmaps[i].glyph_id_ofs_list;
glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_8[rcp];
}
else if (fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY)
{
uint16_t key = rcp;
uint8_t *p = _lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length,
sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
if (p)
{
lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t *)fdsc->cmaps[i].unicode_list);
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
glyph_id = fdsc->cmaps[i].glyph_id_start + ofs;
}
}
else if (fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL)
{
uint16_t key = rcp;
uint8_t *p = _lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length,
sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
if (p)
{
lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t *)fdsc->cmaps[i].unicode_list);
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
const uint8_t *gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list;
glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs];
}
}
/*Update the cache*/
fdsc->last_letter = letter;
fdsc->last_glyph_id = glyph_id;
return glyph_id;
}
fdsc->last_letter = letter;
fdsc->last_glyph_id = 0;
return 0;
}
/**
* Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
* @param font pointer to font
* @param unicode_letter an unicode letter which bitmap should be get
* @return pointer to the bitmap or NULL if not found
*/
const uint8_t *lv_font_get_bitmap_fmt_txt(const lv_font_t *font, uint32_t unicode_letter)
{
if (unicode_letter == '\t')
unicode_letter = ' ';
lv_font_fmt_txt_dsc_t *fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
if (!gid)
return NULL;
const lv_font_fmt_txt_glyph_dsc_t *gdsc = &fdsc->glyph_dsc[gid];
if (fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN)
{
if (gdsc)
return &fdsc->glyph_bitmap[gdsc->bitmap_index];
}
/*Handle compressed bitmap*/
else
{
#if LV_USE_FONT_COMPRESSED
uint32_t gsize = gdsc->box_w * gdsc->box_h;
if (gsize == 0)
return NULL;
uint32_t buf_size = gsize;
/*Compute memory size needed to hold decompressed glyph, rounding up*/
switch (fdsc->bpp)
{
case 1:
buf_size = (gsize + 7) >> 3;
break;
case 2:
buf_size = (gsize + 3) >> 2;
break;
case 3:
buf_size = (gsize + 1) >> 1;
break;
case 4:
buf_size = (gsize + 1) >> 1;
break;
}
if (_lv_mem_get_size(LV_GC_ROOT(_lv_font_decompr_buf)) < buf_size)
{
LV_GC_ROOT(_lv_font_decompr_buf) = lv_mem_realloc(LV_GC_ROOT(_lv_font_decompr_buf), buf_size);
LV_ASSERT_MEM(LV_GC_ROOT(_lv_font_decompr_buf));
if (LV_GC_ROOT(_lv_font_decompr_buf) == NULL)
return NULL;
}
bool prefilter = fdsc->bitmap_format == LV_FONT_FMT_TXT_COMPRESSED ? true : false;
decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], LV_GC_ROOT(_lv_font_decompr_buf), gdsc->box_w, gdsc->box_h,
(uint8_t)fdsc->bpp,
prefilter);
return LV_GC_ROOT(_lv_font_decompr_buf);
#else /* !LV_USE_FONT_COMPRESSED */
return NULL;
#endif
}
/*If not returned earlier then the letter is not found in this font*/
return NULL;
}
static int32_t kern_pair_8_compare(const void *ref, const void *element)
{
const uint8_t *ref8_p = ref;
const uint8_t *element8_p = element;
/*If the MSB is different it will matter. If not return the diff. of the LSB*/
if (ref8_p[0] != element8_p[0])
return (int32_t)ref8_p[0] - element8_p[0];
else
return (int32_t)ref8_p[1] - element8_p[1];
}
static int32_t kern_pair_16_compare(const void *ref, const void *element)
{
const uint16_t *ref16_p = ref;
const uint16_t *element16_p = element;
/*If the MSB is different it will matter. If not return the diff. of the LSB*/
if (ref16_p[0] != element16_p[0])
return (int32_t)ref16_p[0] - element16_p[0];
else
return (int32_t)ref16_p[1] - element16_p[1];
}
static int8_t get_kern_value(const lv_font_t *font, uint32_t gid_left, uint32_t gid_right)
{
lv_font_fmt_txt_dsc_t *fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
int8_t value = 0;
if (fdsc->kern_classes == 0)
{
/*Kern pairs*/
const lv_font_fmt_txt_kern_pair_t *kdsc = fdsc->kern_dsc;
if (kdsc->glyph_ids_size == 0)
{
/* Use binary search to find the kern value.
* The pairs are ordered left_id first, then right_id secondly. */
const uint8_t *g_ids = kdsc->glyph_ids;
uint16_t g_id_both = (gid_right << 8) + gid_left; /*Create one number from the ids*/
uint8_t *kid_p = _lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 2, kern_pair_8_compare);
/*If the `g_id_both` were found get its index from the pointer*/
if (kid_p)
{
lv_uintptr_t ofs = (lv_uintptr_t)(kid_p - g_ids);
ofs = ofs >> 1; /*ofs is for pair, divide by 2 to refer as a single value*/
value = kdsc->values[ofs];
}
}
else if (kdsc->glyph_ids_size == 1)
{
/* Use binary search to find the kern value.
* The pairs are ordered left_id first, then right_id secondly. */
const uint16_t *g_ids = kdsc->glyph_ids;
lv_uintptr_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
uint8_t *kid_p = _lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 4, kern_pair_16_compare);
/*If the `g_id_both` were found get its index from the pointer*/
if (kid_p)
{
lv_uintptr_t ofs = (lv_uintptr_t)(kid_p - (const uint8_t *)g_ids);
ofs = ofs >> 4; /*ofs is 4 byte pairs, divide by 4 to refer as a single value*/
value = kdsc->values[ofs];
}
}
else
{
/*Invalid value*/
}
}
else
{
/*Kern classes*/
const lv_font_fmt_txt_kern_classes_t *kdsc = fdsc->kern_dsc;
uint8_t left_class = kdsc->left_class_mapping[gid_left];
uint8_t right_class = kdsc->right_class_mapping[gid_right];
/* If class = 0, kerning not exist for that glyph
* else got the value form `class_pair_values` 2D array*/
if (left_class > 0 && right_class > 0)
{
value = kdsc->class_pair_values[(left_class - 1) * kdsc->right_class_cnt + (right_class - 1)];
}
}
return value;
}
/**
* Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
* @param font_p pointer to font
* @param dsc_out store the result descriptor here
* @param letter an UNICODE letter code
* @return true: descriptor is successfully loaded into `dsc_out`.
* false: the letter was not found, no data is loaded to `dsc_out`
*/
bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t *font, lv_font_glyph_dsc_t *dsc_out, uint32_t unicode_letter,
uint32_t unicode_letter_next)
{
bool is_tab = false;
if (unicode_letter == '\t')
{
unicode_letter = ' ';
is_tab = true;
}
lv_font_fmt_txt_dsc_t *fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
if (!gid)
return false;
int8_t kvalue = 0;
if (fdsc->kern_dsc)
{
uint32_t gid_next = get_glyph_dsc_id(font, unicode_letter_next);
if (gid_next)
{
kvalue = get_kern_value(font, gid, gid_next);
}
}
/*Put together a glyph dsc*/
const lv_font_fmt_txt_glyph_dsc_t *gdsc = &fdsc->glyph_dsc[gid];
int32_t kv = ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
uint32_t adv_w = gdsc->adv_w;
if (is_tab)
adv_w *= 2;
adv_w += kv;
adv_w = (adv_w + (1 << 3)) >> 4;
dsc_out->adv_w = adv_w;
dsc_out->box_h = gdsc->box_h;
dsc_out->box_w = gdsc->box_w;
dsc_out->ofs_x = gdsc->ofs_x;
dsc_out->ofs_y = gdsc->ofs_y;
dsc_out->bpp = (uint8_t)fdsc->bpp;
if (is_tab)
dsc_out->box_w = dsc_out->box_w * 2;
return true;
}
#endif

View File

@ -1,6 +1,7 @@
#include "oled.h"
#include "oled_font.h"
#include "oled_font_chuc.h"
#include "../../inc/font/lvgl_font.h"
#define BUFPOINT(x, y) (*(dev->buf + x + (y * dev->width)))
#define GET_BIT(x, bit) ((x & (1 << bit)) >> bit)
@ -220,20 +221,24 @@ void OLED_ShowString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *chr, uint8_t si
}
}
void OLED_ShowCHString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *str, uint8_t size) {
uint8_t i, temp, size2, ys = y, xs = x;
void OLED_ShowCHString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *str) {
uint8_t i, temp, size2, ys = y, xs = x, c = x;
uint16_t index;
size2 = (size / 8 + ((size % 8) ? 1 : 0)) * (size); //得到字体一个字符对应点阵集所占的字节数
size2 = Hzk_size * Hzk_size / 8; //得到字体一个字符对应点阵集所占的字节数
while (*str) {
for (index = 0; index < sizeof(Hzk) / 35; index++) {
if (Hzk[index].name[0] == str[0] && Hzk[index].name[1] == str[1])//对比汉字区码位码
for (index = 0; index < sizeof(Hzk) / sizeof(Chinese_t); index++) {
if (Hzk[index].unicode[0] == str[0] && Hzk[index].unicode[1] == str[1])//对比汉字区码位码
{
for (i = 0; i < size2; i++) {
temp = Hzk[index].data[i];
OLED_BSet(dev, xs + (i % size), ys, temp);
if (i == size2 / 2)ys += size / 2;
OLED_BSet(dev, xs, ys, temp);
xs++;
if (xs - c == Hzk_size) {
ys += 8;
xs = c;
c += Hzk_size;
}
}
xs += size;
ys = y;
str++;
str++;
@ -243,6 +248,21 @@ void OLED_ShowCHString(OLED_T *dev, uint8_t x, uint8_t y, uint8_t *str, uint8_t
}
}
}
//
//void OLED_DisplayString(OLED_T *dev, const lv_font_t *font, uint8_t *s, uint16_t x, uint16_t y) {
// uint32_t unicode_letter;
// while (*s) {
// if (font) {
// s += utf8_to_unicode(s, &unicode_letter);
// x += lv_draw_letter(font, unicode_letter, x, y);
// x += 2; //字间距
// } else {
// OLED_ShowChar(dev, x, y, *s, 6);
// x += 6;
// s++;
// }
// }
//}
uint32_t OLED_Pow(uint8_t m, uint8_t n) {
uint32_t result = 1;

View File

@ -18,6 +18,50 @@ def generate_chinese_struct(char_code, font, size):
return result
# from bitarray import bitarray
# # from PIL import Image, ImageDraw
# # from bitarray import bitarray
# def generate_chinese_struct(char_code, font, size):
# height=(size[1] + 7) // 8 * 8
# wight=(size[0] + 7) // 8 * 8
# image = Image.new('1', size, 1)
# draw = ImageDraw.Draw(image)
# draw.text((0, -1), char_code, font=font, fill=0)
# image.show()
# bitmap = bitarray()
# for w in range(size[1]):
# for h in range(size[0]):
# # if h > size[1] or w > size[0]:
# # bitmap.append(False)
# # else:
# if image.getpixel((w, h)) == 0:
# bitmap.append(True)
# print('■', end=' ')
# else:
# bitmap.append(False)
# print('0', end=' ')
# print()
# result = np.zeros(size[0] * size[1] // 8, dtype=np.uint8)
# # for i in range(height):
# # for j in range(wight // 8):
# # for k in range(8):
# # if bitmap[j * 8 + k, i]==1:
# # result[j * height + i] |= (1 << k)
# for h in range(height):
# for w in range(wight):
# if bitmap[w+h]:
# #前景字符(即用来表示汉字笔画的输出字符)
# print('■', end=' ')
# else:
#
# # 背景字符(即用来表示背景的输出字符)
# print('0', end=' ')
# print()
# return result
def generate_chinese_array(input_str, font_str, size):
font = pilfont.truetype(font_str, size=size[1])
chinese_array = []
@ -64,7 +108,7 @@ def generate_and_write_chinese_array_output():
# simsun: 宋体
# kaiti: 楷体
# size = (20, 20)
# size = (20, 20)
# size = (12, 12)
size = (16, 16)
chinese_array = generate_chinese_array("字库生成测试", 'simsun', size)