首页 > 其他分享 >字符编码与freetype移植

字符编码与freetype移植

时间:2022-10-26 14:48:25浏览次数:96  
标签:编码 freetype 字节 buildroot gnueabihf linux arm 移植 sdk

ASCII

ascii是“American Standard Code for Information Interchange”的缩写, 美国信息交换标准代码。

电脑毕竟是西方人发明的,他们常用字母就 26 个,区分大小写、加上标点符号也没超过 127 个,每个字符用一个字节来表示就足够了。一个字节的 7 位就可以表示 128 个数值,在 ASCII 码中最高位永远是 0。

linux-4.18.16/lib/fonts这个目录下就有对应文件。在这里我挑选font_8x16.c

 

 

ANSI

ASNI 是 ASCII 的扩展,向下包含 ASCII。对于 ASCII 字符仍以一个字节来表示.

对于非 ASCII 字符则使用 2 字节来表示。并没有固定的 ASNI 编码.

比如在中国大陆地区, ANSI 的默认编码是 GB2312;

在港澳台地区默认编码是 BIG5。以数值“ 0xd0d6”为例,对于 GB2312 编码它表示“中”;对于 BIG5 编码它表示“ 笢”。

用ANSI编码字符'aa中'的16进制数据

 

UNICODE

在 ANSI 标准中,很多种文字都有自己的编码标准,汉字简体字有 GB2312、繁体字有 BIG5,这难免同一个数值对应不同字符。比如数值“ 0xd0d6”,对于GB2312 编码它表示“中”;对于 BIG5 编码它表示“ 笢”。这造成了使用 ANSI 编码保存的文件,不适合跨地区交流。

UNICODE 编码就是解决这类问题:对于地球上任意一个字符,都给它一个唯一的数值。

  1. ASCII 编码中使用一个字节来表示一个字符,只用到其中的 7 位,最高位恒为 0;
  2. ANSI 编码中,对于 ASCII 字符仍使用一个字节来表示(BIT7 是 0),对于非ASCII 字符一般使用 2 个字节来表示,非 ASCII 字符的数值 BIT7 都是 1

UTF-16 LE

每个 UNICODE 值用 3 字节来表示有点浪费,那只用 2 字节呢?它可以表示2^16=65536 个字符,全世界常用的字符都可以表示了。Little endian 表示小字节序,数值中权重低的字节放在前面,比如字符“ A 中”在 TXT 文件中的数值如下,其中的“ A”使用“0x41 0x00”两字节表示;“中”使用“ 0x2d 0x4e”两字节表示。文件开头的“ 0xff 0xfe”表示“UTF-16 LE”。

 

UTF-16 BE

Big endian 表示大字节序,数值中权重低的字节放在后面,比如字符“ ab中”在 TXT 文件中的数值如下,其中的“ A”使用“ 0x00 0x41”两字节表示;“中”使用“ 0x4e 0x2d”两字节表示。文件开头的“ 0xfe 0xff”表示“UTF-16 BE”

 

UTF8

UTF8 是一种变长的编码方法,有 2 种 UTF8格式的文件:带有头部、不带头部。

 

对于 ASCII 字符用UTF-16有空间浪费、而且文件中有某个字节丢失,这会使得后面所有字符都因为错位而无法显示。UTF8则不会有这样的问题。0x41表示大写字母'A',只用了一个字节。上图中的 3 个字节“ 0xe4 0xb8 0xad”表示的数值是 0x4e2d,对应“中”的 UNICODE 码.

 

上图中, 0xe4 的二进制是“ 11100100”,高位有 3 个 1,表示从当前字节起有 3 字节参与表示 UNICODE;

0xb8 的二进制是“10111000”,高位有 1 个 1,表示从当前字节起有 1 字节参与表示 UNICODE;

0xad 的二进制是“10101101”,高位有 1 个 1,表示从当前字节起有 1 字节参与表示 UNICODE;

除去高位的“ 1110”、“ 10”、“ 10”后,剩下的二进制数组合起来得到“ 01001110001101”,它就是 0x4e2d,即“中”的 UNICODE 值。

使用 UTF8 编码时,即使 TXT 文件中丢失了某些数据,也只会影响到当前字符的显示,后面的字符不受影响。

中文字库移植

-finput-charset -fexec-charset编译选项

我们编写 C 程序时,可以使用 ANSI 编码,或是 UTF-8 编码;在编译程序时,可以使用以下的选项告诉编译器用什么方式编码:

-finput-charset=GB2312

-finput-charset=UTF-8

如果不指定“ -finput-charset”, GCC 就会默认 C 程序的编码方式为 UTF8。

1.用ANSI格式编写编码,vim浏览显示会乱码,用notepad++采用ANSI编码格式浏览.

 

由于编译器默认用utf8编码,所以看到最终打印是乱码的。可以看到“中”的ANSI码是d6 d0。

2.用utf8编写代码

 

 

最终打印是OK的。可以看到“中”的utf8码是e4 b8 ad.

GB2312 转为 UTF-8

 

从上面的输出信息可以看出来, GB2312 的"0xd6 0xd0"可以转换为 UTF-8的“ 0xe4 0xb8 0xad”。而如果把原本就是 UTF-8 格式的 test_charset_utf8.c当作 GB2312 格式,会引起错误

UTF-8 转为 GB2312

 

从 上 面 的 输 出 信 息 可 以 看 出 来 , 如 果 把 原 本 就 是 GB2312 格 式 test_charset_ansi.c 当成UTF-8 格式,会引起错误。而 UTF-8 格式的“中”编码值为“ 0xe4 0xb8 0xad”,可以转换为 GB2312 的“0xd6 0xd0”

HZK16中文字库

HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。符合GB2312标准。

一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符。

HZK16 中是以 GB2312 编码值来查找点阵的,以“中”字为例,它的编码值是“ 0xd6 0xd0”,其中的 0xd6 表示“区码”,表示在哪一个区;其中的 0xd0 表示“位码”,表示它是这个区里的哪一个字符。每一个区有 94 个汉字。区位码从 0xa1 而不是从 0 开始,是为了兼容 ASCII码。

要显示“中”字, 它的 GB2312 编码是 d6d0,它是 HZK16 里第“ (0xd6-0xa1)*94+(0xd0-0xa1)”个字符。(0xd6-0xa1)表示是哪个区,(0xd0-0xa1)表示是哪个位。

如何获取和显示汉字”中“?

fd_hzk16 = open("HZK16", O_RDONLY);
if (fd_hzk16 < 0){
        printf("can't open HZK16\n");
        return -1;
}
if(fstat(fd_hzk16, &hzk_stat)){
        printf("can't get fstat\n");
        return -1;
}
hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
if (hzkmem == (unsigned char *)-1){
        printf("can't mmap for hzk16\n");
        return -1;
}

下载HZK16字库,读取并且mmap字库。

 

 

 

 该函数在 LCD 的(x,y)位置处显示汉字字符 str, str[0]中保存区码、 str[1]中保存位码。

第 4734 行确定该汉字属于哪个区;第 4735 行确实它是该区中哪一个汉字。

第 4736 行确实它的字库地址(第多少个字节):每个区中有 94 个汉字,每个汉字在字库中占据 32 字节。

根据下图来理解字库中每个像素点是如何显示的。

 

总共有十六行,因此需要一个循环 16次的大循环(第 4740 行)。

考虑到一行有两个字节, 在大循环中加入一个 2 次的循环用于区分是哪个字节(第 4741 行)。

最后使用第 3 个循环来处理一个字节中的 8 位(第 4744 行)。对于每一位,它等于 1 时对应的像素被设置为白色,它等于 0 时对应的像素被设置为黑色。需要注意的是根据 x、 y、 i、 j、 b 来计算像素坐标。

测试:

 

注意:使用上述命令时 show_chinese.c 的编码格式必须是 ANSI(GB2312),因为HZK16字库是按照GB2312编码的,否则编译时需要指定“ -fexec-charset=GB2312”。

freetype移植

FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎。

Freetype 是开源的字体引擎库, 它提供统一的接口来访问多种字体格式文件,从而实现矢量字体显示。我们只需要移植这个字体引擎,调用对应的 API 接口,提供字体文件,就可以让 freetype 库帮我们取出关键点、实现闭合曲线, 填充

颜色, 达到显示矢量字体的目的。

这里仅移植freetype库,freetype的使用不做具体展开。可以从 https://www.freetype.org/ 可 以 下 载 到 “ freetype-doc-2.10.2.tar.xz”。

什么是矢量字体

使用点阵字库显示英文字母、汉字时, 大小固定, 如果放大缩小则会模糊甚

至有锯齿出现,为了解决这个问题,引用矢量字体。

第1步 确定关键点,

第2步 使用数学曲线( 贝塞尔曲线) 连接头键点,

第3步 填充闭合区线内部空间。

什么是关键点?以字母“ A”为例

 

再用数学曲线(比如贝塞尔曲线)将关键点都连接起来, 得到一系列的封闭的曲线

 

 最后把封闭空间填满颜色,就显示出一个 A 字母

 

 如果需要放大或者缩小字体,关键点的相对位置是不变的, 只要数学曲线平滑,字体就不会变形。

下载freetype: https://freetype.org/download.html

https://download.savannah.gnu.org/releases/freetype/

freetype 依赖于 libpng, libpng 又依赖于 zlib,所以我们应该:先编译安装 zlib,再编译安装 libpng,最后编译安装 freetype。 但是,有些工具链里有 zlib, 那就不用编译安装 zlib.

下载安装libpng: https://www.linuxfromscratch.org/blfs/view/svn/general/libpng.html

下载安装zlib: https://www.zlib.net/fossils/

1.根据自己的工具链设置环境:

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin

echo 'main(){}'| arm-buildroot-linux-gnueabihf-gcc -E -v -

头文件的系统目录为:

 /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include

 /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include-fixed

 /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/include

 /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include

库文件的系统目录为:

COMPILER_PATH=/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../libexec/gcc/arm-buildroot-linux-gnueabihf/7.5.0/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../libexec/gcc/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/bin/

LIBRARY_PATH=/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/lib/:/media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/

2.编译zlib

编译zlib库时,./configure不允许传入–host参数;不支持的话需要export CC设置为你的arm工具链

export CC=arm-buildroot-linux-gnueabihf-gcc
./configure --prefix=$PWD/tmp
make;make install
cd tmp/lib;ls

将lib和头文件拷贝到工具链目录(或者不拷贝,到时候编译用-L, -I指定即可,运行时指定LIBRARY_PATH)

cp include/* -rf /home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include
cp lib/* -rfd /home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib

3.编译libpng

./configure --host= arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
make
make install
cd tmp/lib;ls

 将lib和头文件拷贝到工具链目录

4.编译freetype

./configure --host= arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
Make
Make  install

注意:如果你的工具链路径不是 /home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot,那么make时会出现类似如下错误。

 

修改自己工具链下的$(TOOLCHAIN)/arm-buildroot-linux-gnueabihf/sysroot/usr/lib目录下编辑libfreetype.la, 替换dependency_libs和libdir的路径。

来自 < http://bbs.100ask.net/question/15908>

 

libfreetype库如下:

 

将lib和头文件拷贝到工具链目录。

5.测试

gcc freetype_show_font.c -I /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include/freetype2/ -L /media/cvitek/robin.lee/my_test/study/weidongshan/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib -lfreetype
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

int fd_fb;
struct fb_var_screeninfo var;        /* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;

/**********************************************************************
 * 函数名称: lcd_put_pixel
 * 功能描述: 在LCD指定位置上输出指定颜色(描点)
 * 输入参数: x坐标,y坐标,颜色
 * 输出参数: 无
 * 返 回 值: 会
 ***********************************************************************/ 
void lcd_put_pixel(int x, int y, unsigned int color)
{
    unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
    unsigned short *pen_16;        
    unsigned int *pen_32;        
    unsigned int red, green, blue;        

    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;

    switch (var.bits_per_pixel)
    {
        case 8:
        {
            *pen_8 = color;
            break;
        }
        case 16:
        {
            /* 565 */
            red   = (color >> 16) & 0xff;
            green = (color >> 8) & 0xff;
            blue  = (color >> 0) & 0xff;
            color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
            *pen_16 = color;
            break;
        }
        case 32:
        {
            *pen_32 = color;
            break;
        }
        default:
        {
            printf("can't surport %dbpp\n", var.bits_per_pixel);
            break;
        }
    }
}

/**********************************************************************
 * 函数名称: draw_bitmap
 * 功能描述: 根据bitmap位图,在LCD指定位置显示汉字
 * 输入参数: x坐标,y坐标,位图指针
 * 输出参数: 无
 * 返 回 值: 无
 ***********************************************************************/ 
void
draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
    FT_Int  i, j, p, q;
    FT_Int  x_max = x + bitmap->width;
    FT_Int  y_max = y + bitmap->rows;

    //printf("x = %d, y = %d\n", x, y);

    for ( j = y, q = 0; j < y_max; j++, q++ )
    {
        for ( i = x, p = 0; i < x_max; i++, p++ )
        {
            if ( i < 0      || j < 0       ||
                i >= var.xres || j >= var.yres )
            continue;

    //image[j][i] |= bitmap->buffer[q * bitmap->width + p];
    lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
    }
    }
}

int main(int argc, char **argv)
{
    wchar_t *chinese_str = L"繁";
    FT_Library          library;
    FT_Face           face;
    int error;
    FT_Vector     pen;
    FT_GlyphSlot  slot;
    int font_size = 24;

    if (argc < 2)
    {
        printf("Usage : %s <font_file> [font_size]\n", argv[0]);
        return -1;
    }

    if (argc == 3)
        font_size = strtoul(argv[2], NULL, 0);
        
    fd_fb = open("/dev/fb0", O_RDWR);
    if (fd_fb < 0)
    {
        printf("can't open /dev/fb0\n");
        return -1;
    }

    if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
    {
        printf("can't get var\n");
        return -1;
    }

    line_width  = var.xres * var.bits_per_pixel / 8;
    pixel_width = var.bits_per_pixel / 8;
    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    if (fbmem == (unsigned char *)-1)
    {
        printf("can't mmap\n");
        return -1;
    }

    /* 清屏: 全部设为黑色 */
    memset(fbmem, 0, screen_size);

    /* 显示矢量字体 */
    error = FT_Init_FreeType( &library );                           /* initialize library */
    /* error handling omitted */
    
    error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
    /* error handling omitted */        
    slot = face->glyph;

    FT_Set_Pixel_Sizes(face, font_size, 0);

    /* 确定座标:
     */
    //pen.x = 0;
    //pen.y = 0;

    /* set transformation */
    //FT_Set_Transform( face, 0, &pen);

    /* load glyph image into the slot (erase previous one) */
    error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
    if (error)
    {
        printf("FT_Load_Char error\n");
        return -1;
    }
    
    draw_bitmap( &slot->bitmap,
                 var.xres/2,
                 var.yres/2);

    return 0;        
}
View Code

标签:编码,freetype,字节,buildroot,gnueabihf,linux,arm,移植,sdk
From: https://www.cnblogs.com/fuzidage/p/16828292.html

相关文章

  • Qt读取ANSI格式文件——利用QTextCodec将其他编码格式转换为Unicode格式
    Qt使用Unicode来表示字符串。但是通常需要访问一些非Unicode格式的字符串,例如打开一个GBK编码的中文文本文件,甚至一些非Unicode编码的日文,俄文等。Qt提供了QTextCodec......
  • 计算机信号码元与编码
    计算机需要处理和传输用户的文字、图片、音频和视频,他们可以统称为消息,数据是运送消息的实体,计算机只能处理二进制数据,也就是比特0和比特1。计算机中的网卡将比特0和比特1......
  • STemWin Lin驱动移植
    显示模组:使用表盘式显示屏驱动ICGC9A01需要给出的uGRAM:113KB主控:STM32WB55RG:1MFlash&256KBSRAM&Quad-SPI(显示方面关键资源)STemWin的驱动模版这次使用Lin......
  • 【759】seq2seq(编码器和解码器)和注意力机制
    参考:动手学深度学习第十八课:seq2seq(编码器和解码器)和注意力机制以机器翻译作为示例讲解的,相关笔记如下:Encoder与Decoder之间的关联,可以是最后的隐含层,或者不同的Attenti......
  • 密码编码
    字符集utfuncoideasciigbk等等等URL编码前端收到url之后进行url编码再发给后端,url编码就是规定什么符号编码什么符号不编码,如果编码是按照ascii规定的,如+等于%2B......
  • base64编码的介绍和使用
    一、base64是什么base64是一种编码方式,可以基于64个可打印字符来表示二进制数据,也就是可以把二进制数据转换成字符串形式来表示,Base64编码是从二进制到字符的过程。在......
  • 前端base64编码格式图片转换为file类型并上传
    将前端的base64编码格式图片转换为file文件,方便传输到后台进行处理。/*将base64转换为blob*/functionbase64ToBlob(dataurl){vararr=dataurl.split(',');var......
  • Python程序员常犯的编码错误(二)
    1.引言本文是Python程序员常犯的编码错误的第二篇,在上一篇中我们重点介绍了常见的五种错误,本文继续介绍该话题,希望大家在日常生活中多多关注。闲话少说,我们直接开始吧!2.......
  • 编码
    理解编码集计算机内部,所有信息最终都是一个二进制。每个二进制位(Bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一......
  • vi编辑器更改文件编码以及模式类型
    ​        作为一名正经运维,我们可能会遇到原文件的编码或者文件模式类型在我们的服务器上无法运行的情况,导致脚本失败甚至无法运行报错的问题,下面说一下检查以及......