您尚未登录。

#1 计算机图形/GUI/RTOS/FileSystem/OpenGL/DirectX/SDL2 » 研究了1天,终于搞清楚如何在LVGL上显示GBK字串,分享一下让大家少踩坑 » 2018-12-01 19:15:43

quop_mike
回复: 22

LVGL版本是5.2,芯片是ESP32【内核是小端】,FATFS使能长文件名,然后同时使能了CP936(支持中文文件名)
问题来了,做了一个MP3播放器,然后在屏幕上显示正在播放的文件名,显示的文件名除了英文全部乱码
研究了一下,由于使能了CP936,所以FATFS读回来的文件名字串应该就是GBK编码的,但是LVGL不支持GBK编码,所以查不到对应的字库来显示,所以全乱码
刚开始以为LVGL直接支持unicode,把GBK强制转换成unicode以后还是乱码,一脸懵逼
搞了好久才弄清楚,LVGL支持的是UTF-8编码格式,简单来说就是英文是1个byte,中文是3byte,那就好办了
思路如下:
对于英文字符,ASCII和GBK还有UTF-8都是一毛一样的,那么
读GBK的字串中的一个byte
       若值<0x80,那么说明目前读取的就是英文字符,直接copy到输出即可

       若值>=0x80,那么说明读取到的已经不是英文字符了,那么先转换为unicode,然后再把unicode转换为UTF-8编码即可

代码如下,均为小端,大端请自行处理

/*------------------
*gbk 指向gbk字串的指针【输入】
*utf8 指向utf8字串的指针【输出】
--------------------*/
void StringGBK2UTF8(uint8_t *gbk, uint8_t *utf8)
{
	int i = 0;
	while (gbk[i] != 0)
	{
		if (gbk[i] < 0x80)
		{
			*utf8 = gbk[i];
			utf8++;
			i++;
		}
		else
		{
			WCHAR unicode = ff_oem2uni((WCHAR)(gbk[i] << 8 | gbk[i+1]), 936);
			int byte = enc_unicode_to_utf8_one(unicode, utf8);
			utf8 += byte;
			i = i + 2;
		}
	}
}

其中ff_oem2uni是FATFS自带的把相应的CODEPAGE编码字符转换成UNICODE字符的函数,不同版本的函数可能略有区别
enc_unicode_to_utf8_one函数是把一个unicode转换为utf-8编码

int enc_unicode_to_utf8_one(unsigned long unic,unsigned char *pOutput)
{  
	assert(pOutput != NULL);  
  
	if (unic <= 0x0000007F)  
	{  
		// * U-00000000 - U-0000007F:  0xxxxxxx  
		*pOutput     = (unic & 0x7F);  
		return 1;  
	}  
	else if (unic >= 0x00000080 && unic <= 0x000007FF)  
	{  
		// * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
		*(pOutput + 1) = (unic & 0x3F) | 0x80;  
		*pOutput     = ((unic >> 6) & 0x1F) | 0xC0;  
		return 2;  
	}  
	else if (unic >= 0x00000800 && unic <= 0x0000FFFF)  
	{  
		// * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 2) = (unic & 0x3F) | 0x80;  
		*(pOutput + 1) = ((unic >>  6) & 0x3F) | 0x80;  
		*pOutput     = ((unic >> 12) & 0x0F) | 0xE0;  
		return 3;  
	}  
	else if (unic >= 0x00010000 && unic <= 0x001FFFFF)  
	{  
		// * U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 3) = (unic & 0x3F) | 0x80;  
		*(pOutput + 2) = ((unic >>  6) & 0x3F) | 0x80;  
		*(pOutput + 1) = ((unic >> 12) & 0x3F) | 0x80;  
		*pOutput     = ((unic >> 18) & 0x07) | 0xF0;  
		return 4;  
	}  
	else if (unic >= 0x00200000 && unic <= 0x03FFFFFF)  
	{  
		// * U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 4) = (unic & 0x3F) | 0x80;  
		*(pOutput + 3) = ((unic >>  6) & 0x3F) | 0x80;  
		*(pOutput + 2) = ((unic >> 12) & 0x3F) | 0x80;  
		*(pOutput + 1) = ((unic >> 18) & 0x3F) | 0x80;  
		*pOutput     = ((unic >> 24) & 0x03) | 0xF8;  
		return 5;  
	}  
	else if (unic >= 0x04000000 && unic <= 0x7FFFFFFF)  
	{  
		// * U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 5) = (unic & 0x3F) | 0x80;  
		*(pOutput + 4) = ((unic >>  6) & 0x3F) | 0x80;  
		*(pOutput + 3) = ((unic >> 12) & 0x3F) | 0x80;  
		*(pOutput + 2) = ((unic >> 18) & 0x3F) | 0x80;  
		*(pOutput + 1) = ((unic >> 24) & 0x3F) | 0x80;  
		*pOutput     = ((unic >> 30) & 0x01) | 0xFC;  
		return 6;  
	}  
  
	return 0;  
}  

#2 Re: 计算机图形/GUI/RTOS/FileSystem/OpenGL/DirectX/SDL2 » 分享一个好用的 littlevgl / lvgl 字体生成工具. 作者 @阿里 » 2018-11-29 12:06:18

晕哥 说:
3038922 说:
晕哥 说:

检查一下字的编码对不对.

电脑上UTF8 啊.
是我如果用BTNM这个模块去显示 陀螺仪 三个字是可以的.
我用label 这个模块 去显示 陀螺仪三个字 是空白....我也不知道为啥.

那其他的字可以吗?

我现在也遇到类似的问题,用List做了一个文件列表,里面会显示扫描到歌曲文件的名字
问题是其他部分,包括list里的前缀{上一首,下一首,正在播放}都正常,但是歌曲名字只有英文能显示,中文一个字都没有

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn