高通字库
版本 V1.0 · 更新于 2026-05-23

6.1 显示资料概述

点阵及灰度显示相关资料

6.1 概述

显示资料包含点阵、灰度、二维码显示参考代码。另外高通为了方便开发人员更加便捷的开发 GUI 文字图像界面,特此开发出划时代的 GUI-LCD 产品,有更加详细的开发资料,高通免费技术支持,可配合 GT-HMI高通灰度字库产品打造炫丽、复杂的文字图形交互界面。

GT-HMI 下载:高通字库-开发工具

点阵字库显示效果点阵字库显示效果

GT-GUI-LCD 相关资料:GT-GUI-LCD 液晶模组

灰度字库显示效果灰度字库显示效果

以下各节提供了从简易显示到完整字符串渲染的示例函数,以及宽度计算、横竖转换和字节逆序等实用工具,帮助开发者快速集成字库芯片的显示功能。

6.2 排置说明

使用字库显示字符前,用户需先确认其排置方式。可通过型号尾缀进行区分: 尾缀为 W 或无尾缀则代表横置横排,尾缀为 Y 代表竖置横排,尾缀为 Z 代表竖置竖排。

横置横排:比如宽度是16bit位,高度是16bit位的字符。那么“横置”指的就是两个字节水平放置,即宽度。“横排”指的是每个字节从做到右横向放两个字节,满两个字节换行继续放,一共有16排,即高度。如下图所示。 描述描述 竖置横排:比如宽度是16bit位,高度是16bit位的字符。那么“竖置”指的就是每个字节都是竖直放置,放16个字节,即宽度。“横排”指的从左到右放16个字节,满16个字节换行继续放,一共有2排,即高度。如下图所示。 描述描述 竖置竖排:比如宽度是24bit位,高度是24bit位的字符。那么“竖置”指的就是每个字节都是竖直放置,放24个字节,即宽度。“竖排”指的是从上到下放3个字节,满3个字节换列继续放,一共有24列,即高度。如下图所示。 描述描述

6.3 WY 简易显示函数

WY_DisplayChar 是一个简化的显示函数,适用于快速原型开发和调试。该函数将字模数据直接写入帧缓冲区,适合分辨率较低或对性能要求不高的场景。

wy_display.c
//点阵数据显示 - 数据高位在前 (字库文字的显示格式)
/**
 * @brief 字符字体数据排置方式
 */
#define FONT_DATA_ARRAY_TYPE_W    (0)
#define FONT_DATA_ARRAY_TYPE_Y    (1)
 /**
  * @brief 字符 点阵数据显示
  * @param pBits 字符数据的缓存
  * @param x_y 坐标
  * @param width 字符宽度
  * @param high  字符高度
  * @param ft_color  字体颜色
  * @param bg_color  背景颜色
  * @param _type 排置方式
  */
void fontDisplay_DZ(unsigned char * pBits, unsigned short x, unsigned short y, unsigned short width, unsigned short high,
    unsigned short ft_color, unsigned short bg_color, unsigned char _type)
{
    unsigned int i, j, k, cnt = 0;
    unsigned char temp;
    unsigned char multiple = 0;
    unsigned short disp_x, disp_y = 0;

    //竖置横排显示Y
    if (FONT_DATA_ARRAY_TYPE_Y == _type) {
        multiple = ((high + 7) >> 3);
        for (i = 0; i < multiple; i++) {
            for (j = 0; j < width; j++) {
                temp = pBits[cnt++];
                for (k = 0; k < 8; k++) {
                    disp_x = (x + j);
                    disp_y = (y + k + (i * 8));
                    if (((temp >> k) & 0x01) == 0) //bg
                    {
                        /* 显示一个像素点 */
                        LCD_Fast_DrawPoint(disp_x, disp_y, bg_color);  //0xFFFF = WHITE
                    }
                    else //font
                    {
                        /* 显示一个像素点 */
                        LCD_Fast_DrawPoint(disp_x, disp_y, ft_color);  //0x0000 = BLACK
                    }
                }
            }
        }
    }
    //横置横排显示W
    else if (FONT_DATA_ARRAY_TYPE_W == _type) {
        multiple = ((width + 7) >> 3);
        for (i = 0; i < high; i++) {
            for (j = 0; j < multiple; j++) {
                temp = pBits[cnt++];
                for (k = 0; k < 8; k++) {
                    disp_x = (x + k + (j * 8));
                    disp_y = (y + i);
                    if (((temp << k) & 0x80) == 0) //bg
                    {
                        /* 显示一个像素点 */
                        LCD_Fast_DrawPoint(disp_x, disp_y, bg_color);
                    }
                    else //font
                    {
                        /* 显示一个像素点 */
                        LCD_Fast_DrawPoint(disp_x, disp_y, ft_color);
                    }
                }
            }
        }
    }
}


/**
 * @brief 测试验证 lcd 在任意坐标画点函数
 */
void test_lcd_draw_point(void)
{
    for (unsigned char x = 0; x < 12; x++) {
        for (unsigned char y = 0; y < 24; y++) {
            /* 显示一个像素点 */
            LCD_Fast_DrawPoint(x, y, 0xFFFF);
        }
    }
}

6.4 灰度矢量文字底色混合显示函数

GrayScale_DisplayChar 提供带 Alpha 混合的灰度矢量文字渲染功能。该函数将前景字模数据与背景图像数据按 Alpha 值进行混合,适合需要在 LCD 屏幕上渲染高质量文字的场合。

grayscale_display.c
#define DISMODE 0 // 1  刷RAM显示  0 打点显示
//描点函数
#if DISMODE
void LCD_WriteRAM(unsigned short RGB_Code)
{
    LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
#else //!DISMODE
static void Gui_DrawPoint(unsigned int x, unsigned int y, unsigned int color)
{
    //显示一个点
    LCD_Fast_DrawPoint(x, y, color);//用户根据自身定义更换
}
#endif //!DISMODE

#define GT_COLOR_GET_R(COLOR)    (((COLOR) >> 11) & 0x1f)
#define GT_COLOR_GET_G(COLOR)    (((COLOR) >> 5) & 0x3f)
#define GT_COLOR_GET_B(COLOR)    (((COLOR)) & 0x1f)
#define GT_UDIV255(x)    (((x) * 0x8081U) >> 0x17)
/**
 * @brief 16位灰度颜色混合
 * @param bg_color 背景色
 * @param ft_color 字体颜色
 * @param gray_scale 灰度值
 * @return unsigned short
 */
static unsigned short gt_color_mix(unsigned short bg_color, unsigned short ft_color, unsigned char gray_scale)
{
    unsigned short mix_color = 0, temp = 0;

    //R
    temp = GT_UDIV255(GT_COLOR_GET_R(ft_color) * gray_scale + GT_COLOR_GET_R(bg_color) * (0xff - gray_scale));
    mix_color = (temp & 0x1f) << 11;

    //G
    temp = GT_UDIV255(GT_COLOR_GET_G(ft_color) * gray_scale + GT_COLOR_GET_G(bg_color) * (0xff - gray_scale));
    mix_color = mix_color | ((temp & 0x3f) << 5);

    //B
    temp = GT_UDIV255(GT_COLOR_GET_B(ft_color) * gray_scale + GT_COLOR_GET_B(bg_color) * (0xff - gray_scale));
    mix_color = mix_color | (temp & 0x1f);

    return mix_color;
}
/**
 * @brief 灰度矢量文字 底色混合 显示函数
 * @param pdata  灰度文字数据
 * @param x_y_w_h  x,y 显示起始坐标; w 宽度, h 高度
 * @param grade  灰度阶级[1阶/2阶/3阶/4阶]
 * @param bg_color  背景颜色
 * @param ft_color  字体颜色
 */
void display_gray_vector_font(unsigned char * pdata, unsigned short x, unsigned short y, unsigned short w, unsigned short h,
    unsigned char grade, unsigned short bg_color, unsigned short ft_color)
{
    unsigned short w_byte = (w + 7) >> 3;
    unsigned short x_s = x, idx = 0, i = 0, j = 0;
    unsigned short mix_color = 0;
    unsigned char gray_data = 0, gray_scale = 0;
    w = w_byte << 3;

#if DISMODE
    LCD_Set_Window(x, y, w, h);	//设置窗口
    LCD_WriteRAM_Prepare();		//开始写入GRAM
#endif //!DISMODE

    if (2 == grade || 4 == grade) {
        for (i = 0; i < h * w_byte * grade; i++) {
            gray_data = pdata[idx++];//取一个字节灰度数据
            for (j = 0; j < (8 / grade); j++) {
                gray_scale = (gray_data >> (8 - grade)) * (0xFF / ((1 << grade) - 1)); //获取该点灰阶值
                gray_data <<= grade;

                if (gray_scale == 0) { //获取该点颜色值
                    mix_color = bg_color;
                }
                else if (0xff == gray_scale) {
                    mix_color = ft_color;
                }
                else {
                    mix_color = gt_color_mix(bg_color, ft_color, gray_scale);
                }

#if DISMODE //显示
                //写RAM的方式16位数据
                LCD_WriteRAM(mix_color);
#else //!DISMODE
                if (x < x_s + w) {
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
                else {
                    x = x_s;
                    y++;
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
#endif //!DISMODE
            }
        }
    }
    else if (3 == grade) {
        for (i = 0; i < h * w_byte; i++) {
            gray_data = pdata[idx];//取一个字节灰度数据
            for (j = 0; j < 8; j++) {
                if (2 == j) {//计算灰阶值
                    gray_data = (pdata[idx] & 0x03) << 1;
                    idx++;
                    gray_scale = (gray_data | (pdata[idx] >> 7)) * (0xFF / ((1 << 3) - 1)); //(前字节后两位 | 后字节前1位) * 每份比例
                    gray_data = pdata[idx] << 1;
                }
                else if (5 == j) {
                    gray_data = (pdata[idx] & 0x01) << 2;
                    idx++;
                    gray_scale = (gray_data | (pdata[idx] >> 6)) * (0xFF / ((1 << 3) - 1));//(前字节后1位 | 后字节前2位) * 每份比例
                    gray_data = pdata[idx] << 2;
                }
                else {
                    gray_scale = (gray_data >> 5) * (0xFF / ((1 << 3) - 1));
                    gray_data <<= 3;
                }

                if (gray_scale == 0) { //根据灰阶值获取该点颜色值
                    mix_color = bg_color;
                }
                else if (0xfc == gray_scale) {   //0xff/7*7 = 0xfc
                    mix_color = ft_color;
                }
                else {
                    mix_color = gt_color_mix(bg_color, ft_color, gray_scale);
                }
#if DISMODE //显示
                //写RAM的方式16位数据
                LCD_WriteRAM(mix_color);
#else //!DISMODE
                if (x < x_s + w) {
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
                else {
                    x = x_s;
                    y++;
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
#endif //!DISMODE
            }
            idx++;
        }
    }
    else {
        for (i = 0; i < h * w_byte; i++) {
            gray_data = pdata[idx++];//取一个字节灰度数据
            for (j = 0; j < 8; j++) {
                if (gray_data & 0x80) {
                    mix_color = ft_color;
                }
                else {
                    mix_color = bg_color;
                }
                gray_data <<= 1;
#if DISMODE //显示
                //写RAM的方式16位数据
                LCD_WriteRAM(mix_color);
#else //!DISMODE
                if (x < x_s + w) {
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
                else {
                    x = x_s;
                    y++;
                    Gui_DrawPoint(x, y, mix_color);    //打点方式
                    x++;
                }
#endif //!DISMODE
            }
        }
    }
}

6.5 字符串显示例子

LCD_ShowString 是一个完整的字符串显示例程,支持换行符处理。该函数遍历字符串中的每个字符,通过 UTF8 解码获取 Unicode 编码,从字库芯片读取字模数据,再调用简易显示函数绘制到屏幕上。

lcd_string.c

unsigned char jtwb[128] = "收款退款交易查询终端管理";	//每个中文字符实际由两个字节组成, 对应GBK等编码

unsigned char pBits[512];

/*
    功能:字符串显示
    text:字符串
    (x,y):显示的起始坐标
*/
void show_char(unsigned char * text, unsigned int x, unsigned int y)
{
    while (*text != '\0')//判断是否是结尾
    {
        if (*text < 0x80) {  //ASCII 码 *text是ASCII码
            ASCII_GetData(*text, ASCII_8X16_A, pBits);	//示例, 按实际函数名进行修改
            DisZK_DZ_W(x, y, 8, 16, BLACK, WHITE, pBits, 1);  //显示8X16点ASCII函数
            x = x + 8;
        }
        else {  //汉字编码*text是汉字编码的高位,*(text+1)是汉字编码的低位
            gt_16_GetData(*text, *(text + 1), pBits);	//示例, 按实际函数名进行修改
            DisZK_DZ_W(x, y, 16, 16, BLACK, WHITE, pBits, 1);  //显示汉字
            x = x + 16;
            text++;
        }
        text++;
    }
}

void main()
{
    unsigned char Data_buf[512];
    show_char(jtwb, 0, 0);


#if 0	//汉字字符串
    unsigned short arr[3] = { 0xb0a1, 0xb0a2, 0xb0a3 };	//对应中文编码 , "啊": 0xb0a1 ...
    for (i = 0; i < sizeof(arr), i++) {
        gt_24_data(arr[i] >> 16, arr[i] & 0xff, Data_buf);
        DisZK_DZ_W(j, 0, 24, 24, BLACK, WHITE, Data_buf, 1);	//显示函数
        j += 24;
    }
#endif
}


char * itoa(int num, char * str, int radix)
{
    char index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表
    unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
    int i = 0, j, k;//i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。

    //获取要转换的整数的绝对值
    if (radix == 10 && num < 0)//要转换成十进制数并且是负数
    {
        unum = (unsigned)-num;//将num的绝对值赋给unum
        str[i++] = '-';//在字符串最前面设置为'-'号,并且索引加1
    }
    else unum = (unsigned)num;//若是num为正,直接赋值给unum

    //转换部分,注意转换后是逆序的
    do {
        str[i++] = index[unum % (unsigned)radix];//取unum的最后一位,并设置为str对应位,指示索引加1
        unum /= radix;//unum去掉最后一位

    } while (unum);//直至unum为0退出循环

    str[i] = '\0';//在字符串最后添加'\0'字符,c语言字符串以'\0'结束。

    //将顺序调整过来
    if (str[0] == '-') k = 1;//如果是负数,符号不用调整,从符号后面开始调整
    else k = 0;//不是负数,全部都要调整

    char temp;//临时变量,交换两个值时用到
    for (j = k;j <= (i - 1) / 2;j++)//头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1
    {
        temp = str[j];//头部赋值给临时变量
        str[j] = str[i - 1 + k - j];//尾部赋值给头部
        str[i - 1 + k - j] = temp;//将临时变量的值(其实就是之前的头部值)赋给尾部
    }

    return str;//返回转换后的字符串

}

6.6 一维码调用示例

字库芯片内置一维码(条形码)绘制功能。GT_DrawBarcode 函数通过配置 GT_BARCODE_PARAM 结构体,可快速在屏幕上绘制 CODE128 等格式的条形码。

barcode_example.c
#include "stdio.h"
#include "string.h"

/**************************************
arr[] : 13个数组
**************************************/
void  BAR_codeEAN13(unsigned int x, unsigned int y, unsigned char arr[])
{
	unsigned char buff_temp[60];
	unsigned long *tmp ;
	unsigned char i = 0;

	tmp = BAR_CODE_EAN13(arr);

	for(i = 0;i < 13;i++)
	{
		memset(buff_temp,0,sizeof(buff_temp));
		r_dat_bat(*tmp, 54, buff_temp);
		DisZK_DZ_W(x,y,16,28,BLACK,WHITE,&buff_temp[2],1);
		x+=buff_temp[1];
		tmp++;
	}
}


/**************************************
ascii_arr[] : 字符数组 ASCII
arr_len:	字符数组的长度
Code 39码只接受如下43个有效输入字符:
1. 26个大写字母(A – Z);
2. 十个数字(0 – 9);
3. 连接号(-),句号(.),空格,美圆符号($),斜扛(/),加号(+)以及百分号(%)。其余的输入将被忽略。
**************************************/
void BAR_codeEAN39(unsigned int x, unsigned int y, unsigned char ascii_arr[], unsigned int arr_len) {
	unsigned char buff_tmp[50], i;
	
	for(i=0; i<arr_len; i++) {
		BAR_CODE39(ascii_arr[i], buff_tmp);
		DisZK_DZ_W(x,y,16,22,BLACK,WHITE,&buff_tmp[0],1);
		x+=11;
	}
}

/**************************************
arr[]: 条形码编码 整数
arr_len: 数组长度
flag: 起始符有3种模式
	当flag=1时为Code-128-A;
	当flag=2时为Code-128-B;
	当flag=3时为Code-128-C;
Code128编码表参考: https://blog.csdn.net/rodulf/article/details/51276820
**************************************/
void BAR_codeEAN128(unsigned int x, unsigned y, unsigned char arr[], unsigned int arr_len, unsigned char flag) {
	unsigned char buff_tmp[60];
	unsigned long *tmp;
	unsigned char i=0;
	const unsigned char verify = 3;
	
	tmp = BAR_CODE128(arr, arr_len, flag);
	
	for(i=0; i<arr_len+verify; i++) {
		memset(buff_tmp, 0, sizeof(buff_tmp));
		r_dat_bat(*tmp, 40, buff_tmp);
		DisZK_DZ_W(x, y, 16, 20, BLACK, WHITE, &buff_tmp[0], 1);	//显示函数, 根据实际修改, 参考显示函数文件
		x+=11;	//可修改
		tmp++;
	}
}

//
#if 0
int main(void) {
	
	unsigned char code[13]={6,9,0,1,6,8,7,5,8,2,4,4,2};
	unsigned char code1[13]={6,9,3,8,7,0,9,3,0,0,4,4,9};
	unsigned char code2[13]={'A','1','9','3','4','7','$',' ','-','5','8','3','E'};
	unsigned char code3[13] = {16,33,45,31,27,26,40};
	
	#if 01
	BAR_codeEAN13(0, 0, code);
	BAR_codeEAN13(0, 0, code1);
	#endif
	
	#if 01
	BAR_codeEAN39(0, 150, code2, 13);
	#endif
	
	#if 01
	BAR_codeEAN128(0, 200, code3, 7, 1);
	#endif
	
	return 0;
}

#endif

6.7 获取宽度_W简易

WY_GetStringWidth 是一个简化的字符串宽度计算函数,适用于等宽字体场景。该函数假设每个字符宽度等于字号大小,适合快速估算字符串显示所需的像素宽度。

wy_string_width.c
/**
 * @brief 得到灰度文字的宽度 (W横置横排)
 *
 * @param pdata 文字数据
 * @param dot_w 文字宽度     例如:48x48大小的文字 dot_w = 48
 * @param dot_h 文字高度         例如:48x48大小的文字 dot_h = 48
 * @param gray 取值: 1 / 2 / 4
 * @return int 实际文字宽度
 */
int _get_font_width(uint8_t * pdata, uint16_t dot_w, uint16_t dot_h, uint16_t gray)
{
    uint16_t byte_w, i;
    int j, len;
    uint8_t tmp = 0;

    byte_w = ((dot_w + 7) >> 3) * gray;

    for (j = byte_w - 1; j >= 0; j--) {
        tmp = 0;
        for (i = 0; i < dot_h; i++) {
            tmp |= pdata[i * byte_w + j];
        }
        if (0 != tmp) {
            for (i = 0; i < 8; i++) {
                if ((tmp >> i) & 0x01) {
                    break;
                }
            }

            len = ((j / gray) * 8) + ((j % gray) * 8 + (8 - i)) / gray;
            //
            if (len >= dot_h) {
                continue;
            }

            return len;
        }
    }

    return dot_w;
}

6.8 获取宽度

GT_GetStringWidth 是完整的字符串宽度计算函数,通过查询每个字符的实际宽度来精确累加。与简易版本不同,该函数使用 GT_GetCharWidth 获取每个字符的真实像素宽度,适用于非等宽字体场景。

string_width.c
/**
 @p: 字符点阵数组
 @zfwidth: 	显示字符的宽度
 @zfhigh:	显示字符的高度
 @return:	字符的实际最大宽度
*/
unsigned int get_width(unsigned char * p, unsigned int zfwidth, unsigned int zfhigh)
{
    unsigned char * q;
    unsigned int i, j, tem, tem1, witdh1 = 0, witdh2 = 0;
    q = p;
    for (i = 0;i < zfwidth / 16;i++) {
        tem = 0;
        tem1 = 0;
        for (j = 0;j < zfhigh;j++) {
            tem = (*(q + j * (zfwidth / 8) + i * 2) | (*(q + 1 + j * (zfwidth / 8) + i * 2)) << 8);
            tem1 = tem1 | tem;
        }
        witdh1 = 0;
        for (j = 0;j < 16;j++) {
            if (((tem1 << j) & 0x8000) == 0x8000) {
                witdh1 = j;
            }
        }
        witdh2 += witdh1;
    }
    return witdh2;
}

//
/**
 @p: 字符点阵数组
 @zfwidth: 	显示字符的宽度
 @zfhigh:	显示字符的高度
 @return:	字符的实际最大宽度
*/
unsigned int get_width(unsigned char * p, unsigned int zfwidth, unsigned int zfhigh)
{
    int high_i = 0, width_i = 0;
    unsigned int record = 0;
    unsigned int max_width = 0;

    for (width_i = (zfwidth * 2) - 1; width_i >= 0; width_i--) {
        for (high_i = 0;high_i <= zfhigh;high_i++) {

            record = p[(zfwidth * high_i * 2) + width_i];

            if (record) {
                max_width = width_i;
                break;
            }

        }
        if (record) {
            //	max_width = width_i;
            break;
        }
    }
    if (width_i >= 0)
        return max_width / 2 + 1;
    else
        return zfwidth / 3;

}
/**************/


/**
 只适用横置横排
 @p: 字符点阵数组
 @zfwidth: 	显示字符的宽度
 @zfhigh:	显示字符的高度
 @return:	字符的实际最大宽度
*/
unsigned int get_width_1(unsigned char * p, unsigned int zfwidth, unsigned int zfhigh)
{
    unsigned char width_Byte = zfwidth / 8;
    unsigned char record = 0;
    unsigned int max_width = 0, cnt = 0;
    int i, j, m;

    for (i = width_Byte - 1; i >= 0; i--) {
        record = 0;
        cnt = i;
        for (j = 0; j < zfhigh; j++) {
            record |= p[cnt];
            cnt += width_Byte;
        }
        if (record != 0) {
            break;
        }
    }
    for (m = 0; m < 8; m++) {
        if ((record >> m) & 0x01) {
            max_width = (8 - m) + i * 8;
            break;
        }
    }
    return max_width;
}

6.9 横竖转换

GT_MatrixTranspose 将点阵字模数据进行横竖方向转换。当需要将横向扫描的字模数据转换为纵向扫描格式时(或反之),可调用此函数完成矩阵转置操作。

matrix_transpose.c
#define  HZ_MODE00 0//竖置横排(Y)
#define  HZ_MODE01 1//竖置竖排(Z)
#define  HZ_MODE10 2//横置横排(W)
#define  HZ_MODE11 3//横置竖排(X)

#define  HZ_MODE4  4//Y-->W
//条件putdata的数据写入X,Y的LCD显示缓冲RAM中
/*
*getdate: 转换后的字形数据
*putdate: 转换签订字形数据
*width:	字宽
*high:	字高
*style: 转换功能的选择, HZ_MODE00 0//竖置横排(Y)
                        HZ_MODE01 1//竖置竖排(Z)
                        HZ_MODE10 2//横置横排(W)
                        HZ_MODE11 3//横置竖排(X)
                        HZ_MODE4  4//Y-->W

*使用示例:lcdram_map(getdate,putdate,32,32,HZ_MODE4);//将32x32的字形数据由Y排置(竖置横排)转换成W排置(横置横排)保存在getdate数组中
*/
void lcdram_map(u8 * getdate, u8 * putdata, u8 width, u8 high, u8 style)
{
    u16 i, j, hbyte, wbyte;
    unsigned char i_8, j_8;
    wbyte = (width + 7) / 8;
    hbyte = (high + 7) / 8;
    //--------------------------------------------------------------------------
    // Y--> W; Y-->X; Y-->Z;
    //--------------------------------------------------------------------------
    if (style == HZ_MODE4)	//竖置横排 转 横置横排 ( Y-->W )
    {
        for (i = 0; i < high; i++)
            for (j = 0; j < width; j++) {
                i_8 = i / 8;
                if ((*(putdata + i_8 * width + j) & (0x01 << (i % 8))) > 0)
                    getdate[wbyte * i + j / 8] |= (0x80 >> (j % 8));
                else
                    getdate[wbyte * i + j / 8] &= (~(0x80 >> (j % 8)));
            }
    }
    //--------------------------------------------------------------------------
    // W--> Y;  W-->Z;W-->X;
    //--------------------------------------------------------------------------

    if (style == HZ_MODE00)	//竖置横排 (W--> Y)
    {
        for (i = 0; i < high; i++)
            for (j = 0; j < width; j++) {
                i_8 = i / 8;
                if ((*(putdata + wbyte * i + j / 8) & (0x80 >> (j % 8))) > 0)
                    getdate[i_8 * width + j] |= (0x01 << (i % 8));
                else
                    getdate[i_8 * width + j] &= (~(0x01 << (i % 8)));
            }
    }
    else if (style == HZ_MODE01)	//竖置竖排 (W-->Z)
    {
        for (i = 0; i < high; i++)
            for (j = 0; j < width; j++) {
                if ((*(putdata + wbyte * i + j / 8) & (0x80 >> (j % 8))) > 0)
                    getdate[j * hbyte + i / 8] |= (0x01 << (i % 8));
                else
                    getdate[j * hbyte + i / 8] &= (~(0x01 << (i % 8)));
            }
    }
    else if (style == HZ_MODE11)//横置竖排 (W-->X)
    {
        for (i = 0; i < high; i++)
            for (j = 0; j < width; j++) {
                j_8 = j / 8;
                if ((*(putdata + wbyte * i + j / 8) & (0x80 >> (j % 8))) > 0)
                    getdate[j_8 * high + i] |= (0x80 >> (j % 8));
                else
                    getdate[j_8 * high + i] &= (~(0x80 >> (j % 8)));
            }
    }
    else if (style == HZ_MODE10)//横置横排 做镜像(W-->W')
    {
        for (i = 0; i < high; i++)
            for (j = 0; j < width; j++) {
                if ((*(putdata + wbyte * i + j / 8) & (0x80 >> (j % 8))) > 0)
                    *(getdate + wbyte * i + (width - j) / 8) |= (0x80 >> ((width - j) % 8));
                else
                    *(getdate + wbyte * i + (width - j) / 8) &= ~(0x80 >> ((width - j) % 8));
            }
    }
}

//竖直竖排转横置横排 Z转W
/*
*getdate: 转换后的字形数据
*putdate: 转换签订字形数据
*width:	字宽
*high:	字高
*/
void Z2W(unsigned char * getData, unsigned char * putData, unsigned char width, unsigned char height) {

    unsigned char line, lie;
    unsigned int i = 0, count = 0, mark = 0;	//i控制putData的下标, count控制getData的下标

    for (line = 0; line < height; line++) {	//控制行
        for (lie = 0; lie < width; lie++) {	//控制列
            getData[count] = (unsigned char)(getData[count] << 0x01);	//准备接收下一下
            if (putData[i] & (0x01 << (line % 8)))
                getData[count] += 1;	//先取低位, 存新数组内
            else
                getData[count] += 0;
            i += height >> 3;	//下一列
            if (lie % 8 == 7) {
                count++;
            }
        }
        if (line % 8 == 7) {
            i = ++mark;
        }
        else
            i = mark;
    }
}

//竖直竖排转竖置横排(Z->Y)
/*
*getdate: 转换后的字形数据
*putdate: 转换签订字形数据
*width:	字宽
*high:	字高
*/
void Z2Y(unsigned char * getData, unsigned char * putData, unsigned char width, unsigned char height) {
    unsigned char line = height >> 3;
    unsigned int i = 0, count = 0, mark_count = 0, sum = width * height >> 3;

    for (i = 0;i < sum;i++) {
        getData[count] = putData[i];
        count += width;
        if (((i + 1) % line) == 0)
            count = ++mark_count;
    }
}

//竖置横排转竖直竖排  Y转Z
/*
*getdate: 转换后的字形数据
*putdate: 转换签订字形数据
*width:	字宽
*high:	字高
*/
void Y2Z(unsigned char * getData, unsigned char * putData, unsigned char width, unsigned char height) {
    unsigned char line = height >> 3;
    unsigned int i = 0, count = 0, mark_count = 0, sum = width * height >> 3;

    for (i = 0; i < sum; i++) {
        getData[count] = putData[i];
        count += line;
        if (((i + 1) % width) == 0) {
            count = ++mark_count;
        }
    }
}

6.10 字节逆序

GT_ReverseByte 将字节的位序进行反转(bit 7 与 bit 0 交换,bit 6 与 bit 1 交换,以此类推)。当字模数据的位序与显示设备要求不一致时,可调用此函数进行转换。

reverse_byte.c
/*
    p:需要逆置的数据地址
    len:需要逆置的数据长度
*/
void byte_cov(unsigned char * p, unsigned long len)
{
    unsigned long i;
    unsigned char tem;
    for (i = 0;i < len;i++) {
        tem = p[i];
        p[i] = ((tem & 0x01) << 7) | ((tem & 0x02) << 5) | ((tem & 0x04) << 3) | ((tem & 0x08) << 1)  \
            | ((tem & 0x10) >> 1) | ((tem & 0x20) >> 3) | ((tem & 0x40) >> 5) | ((tem & 0x80) >> 7);
    }
}

/**
 * @brief Y排置字体镜像
 * dz_data:字形数据
 * len:数据长度
 */
void y_mirror(unsigned char * dz_data, unsigned long len)
{
#if 0
    unsigned long i;
    unsigned char tem;

    for (i = 0; i < len; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[len - i - 1];
        dz_data[len - i - 1] = tem;
    }
#else
    unsigned long i, mid;
    unsigned char tem;

    mid = len >> 1;

    for (i = 0; i < mid; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[mid - 1 - i];
        dz_data[mid - 1 - i] = tem;
    }

    for (i = mid; i < len; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[len - 1 - i];
        dz_data[len - 1 - i] = tem;
    }

    for (i = 0; i < mid; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[mid + i];
        dz_data[mid + i] = tem;
    }
#endif
}


/**
 * @brief Y排置字体镜像
 * dz_data:字形数据
 * len:数据长度
 */
void y_mirror(unsigned char * dz_data, unsigned long len)
{
    unsigned long i, mid;
    unsigned char tem;

    mid = len >> 1;

    for (i = 0; i < mid; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[mid - 1 - i];
        dz_data[mid - 1 - i] = tem;
    }

    for (i = mid; i < len; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[len - 1 - i];
        dz_data[len - 1 - i] = tem;
    }

    for (i = 0; i < mid; i++) {
        tem = dz_data[i];
        dz_data[i] = dz_data[mid + i];
        dz_data[mid + i] = tem;
    }
}

6.11 不等宽字符的显示

1.点阵/灰度字库芯片不等宽字符显示处理

点阵/灰度字库 不等宽字符排列格式

以16点阵ASCII不等宽字符为例(不等宽字符类型详见各字库芯片宏定义中的注释),16点阵不等宽字符的信息需要34个字节(BYTE 0 – BYTE33)来表示。

存储格式

由于字符是不等宽的,因此在存储格式中BYTE0~ BYTE1存放文字宽度数据,BYTE2-33存放点阵数据。具体格式见下图:

具体数据格式图具体数据格式图

存储结构

不等宽字符的点阵存储宽度是以BYTE(8bit)为单位取整的,根据不同字符宽度会出现相应的空白区。根BYTE0~ BYTE1所存放点阵的实际宽度数据,即x坐标加上该字符的宽度数据,做为下一个字符显示的x轴的起始位置,

例如:ASCII圆角字符B

0-33BYTE的全部数据是: 00 0C 00 00 00 00 00 00 7F 80 7F C0 60 C0 60 C0 60 C0 7F 80 7F C0 60 E0 60 60 60 60 7F C0 7F 80 00 00

其中头两个字节:

BYTE0~ BYTE1: 00 0C 为ASCII圆角字符B的点阵宽度数据,即:12位宽度。字符后面有4位空白区,可以在排版下一个字时考虑到这一点,将下一个字的起始位置前移。即x坐标加上该字符的宽度数据,即为下一个字符的x轴的起始位置,

BYTE2-33: 00 00 00 00 00 00 7F 80 7F C0 60 C0 60 C0 60 C0 7F 80 7F C0 60 E0 60 60 60 60 7F C0 7F 80 00 00 为ASCII圆角字符B的点阵数据。

不等宽示例代码

/*
 * 示例:使用 ASCII_12_A 显示 "Ab"。
 * ASCII_12_A 是不等宽 12x12 Arial 字体。
 */
unsigned char DZ_Data[512];
int x_position = 10, y_position = 10;
unsigned int a_width = 0;
/* 读取并显示字符 'A'。 */
memset(DZ_Data, 0, sizeof(DZ_Data));
ASCII_GetData(0x41, ASCII_12_A, DZ_Data);
a_width = (DZ_Data[0] << 8) | DZ_Data[1];
LCD_Display_hz(&DZ_Data[2], x_position, y_position, 16, 12, 1);

/* 读取并显示字符 'b',x 坐标使用 'A' 的实际宽度计算。 */
memset(DZ_Data, 0, sizeof(DZ_Data));
ASCII_GetData(0x62, ASCII_12_A, DZ_Data);
LCD_Display_hz(&DZ_Data[2], x_position + a_width, y_position, 16, 12, 1);

2 矢量字库芯片不等宽字符显示处理

如果使用get_font函数则打开“05_屏幕显示资料\获取宽度.c”,直接拷贝获取宽度的代码。如果使用get_font_gray函数,则打开“05_屏幕显示资料\获取灰度字形的宽度”拷贝获取灰度宽度的代码。 代码所在路径截图代码所在路径截图

具体的代码以及参数含义如下文所示:

/**
 * @brief Get the width object
 * 
 * @param p 字符数据数组首地址
 * @param zfwidth 获取字符时填写的宽度
 * @param zfhigh 获取字符时填写的高度
 * @return unsigned int 实际宽度
 */
unsigned int get_width(unsigned char *p,unsigned int zfwidth,unsigned int zfhigh )
{
  unsigned char *q;
  unsigned int i,j,tem,tem1,witdh1=0,witdh2=0;
  q=p;
  for (i=0;i<zfwidth/16;i++)
  {
      tem=0;
    tem1=0;
    for (j=0;j<zfhigh;j++)
    {
       tem=(*(q+j*(zfwidth/8)+i*2)|(*(q+1+j*(zfwidth/8)+i*2))<<8);
       tem1=tem1|tem;
    }
    witdh1=0;
    for (j=0;j<16;j++)
    {
      if (((tem1<<j)&0x8000)==0x8000)
      {
        witdh1=j;
      }
    }
    witdh2+=witdh1;
  }
  return witdh2;
}
/**
 * @brief 获取灰度字库宽度
 *
 * @param data 带灰度的字符数据数组
 * @param dot_w 获取字符时填写的宽度    
 * @param dot_h 获取字符时填写的高度
 * @param gray 取值: 1 / 2 / 4
 * @return int 实际宽度
 */
uint16_t get _width_gray(const uint8_t* data, uint16_t dot_w, uint16_t dot_h, uint8_t gray)
{
    uint16_t byte_w, i;
    int j, len;
    uint8_t tmp = 0;
    byte_w = ((dot_w + 7) >> 3) * gray;
    for(j = byte_w-1;j >= 0; j--) {
        tmp = 0;
        for(i = 0; i < dot_h; i++) {
            tmp |= data[i*byte_w + j];
        }
        if(0 != tmp) {
            for(i = 0; i < 8; i++){
                if((tmp >> i)&0x01){
                    break;
                }
            }
            len = ((j / gray) * 8) + ((j%gray)*8+(8-i))/gray;
            if (len >= dot_h) {
                continue;
            }
            return len;
        }
    }
    return dot_w;
}

矢量输出灰度数据时获取宽度示例:

    unsigned int *tmp, real_w = 0;
    tmp = get_Font_Gray(pBits,(*text) < 0x80?VEC_FT_ASCII_STY:VEC_SONG_STY,*text,size, size);   // 
    real_w = get_width_gray(pBits,tmp[0],size, tmp[1]); //获取灰度的宽度
    Gray_Display_hz(pBits,x,y,tmp[0],size,tmp[1]);
    x = x + real_w;

矢量输出点阵数据时获取宽度示例:

VECFONT_ST font_st = {.fontCode = 0x41, .type = VEC_FT_ASCII_STY, .size = 16, .thick = 16, .zkBuffer = {0}};
get_font_st(&font_st);  //获取矢量字符数据
int width = get_width(font_st.zkBuffer, 16, 16);  //获取实际的字符宽度
Display_W(font_st.zkBuffer, 100, 100, width, 16);


char pBits[256] = {0};
get_font(pBits, VEC_FT_ASCII_STY, 0x41, 16, 16, 16);    //获取矢量字符数据
int width = get_width(pBits, 16, 16);  //获取实际的字符宽度
Display_W(pBits, 100, 100, width, 16);

注:无论点阵/灰度/矢量字库芯片,中文的宽度都是等宽。