0%

字符编码与显示

基本概念

字符

各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。 也就是说,它是一个信息单位,一个数字是一个字符,一个文字是一个字符,一个标点符号也是一个字符。

字节

字节是一个8bit的存储单元,取值范围是0x00~0xFF。 根据字符编码的不同,一个字符可以是单个字节的,也可以是多个字节的。

字符集

字符的集合就叫字符集。不同集合支持的字符范围自然也不一样,譬如ASCII只支持英文,GB18030支持中文等等

在字符集中,有一个码表的存在,每一个字符在各自的字符集中对应着一个唯一的码。但是同一个字符在不同字符集中的码是不一样的,譬如字符“中”在Unicode和GB18030中就分别对应着不同的码(2001354992)。

字符编码

定义字符集中的字符如何编码为特定的二进制数,以便在计算机中存储。 字符集和字符编码一般一一对应(有例外)

譬如GB18030既可以代表字符集,也可以代表对应的字符编码,它为了兼容ASCII码,编码方式为code大于255的采用两位字节(或4字节)来代表一个字符,否则就是兼容模式,一个字节代表一个字符。(简单一点理解,将它认为是现在用的的中文编码就行了)

字符集与字符编码的一个例外就是Unicode字符集,它有多种编码实现(UTF-8,UTF-16,UTF-32等)

字符集与字符编码的快速区分

  • ASCII码是一个字符集,同时它的实现也只有一种,因此它也可以指代这个字符集对应的字符编码
  • GB18030是一个字符集,主要是中国人为了解决中文而发明制定的,由于它的实现也只有一种,所以它也可以指代这个字符集对应的字符编码
  • Unicode是一个字符集,为了解决不同字符集码表不一致而推出的,统一了所有字符对应的码,因此在这个规范下,所有字符对应的码都是一致的(统一码),但是统一码只规定了字符与码表的一一对应关系,却没有规定该如何实现,因此这个字符集有多种实现方式(UTF-8,UTF-18,UTF-32),因此这些实现就是对应的字符编码。 也就是说,Unicode统一约定了字符与码表直接一一对应的关系,而UTF-8是Unicode字符集的一种字符编码实现方式,它规定了字符该如何编码成二进制,存储在计算机中。

不同字符编码的字符是如何进行转换的

  • 如果是相同字符集,由于相同字符集中的码都是一样的,所以只需要针对不同的编码方式转变而已。譬如UTF-16转UTF-8,首先会取到当前需要转换的字符的Unicode码,然后将当前的编码方式由双字节(有4字节的拓展就不赘述了),变为变长的1,2,3等字节
  • 如果是不同的字符集,由于不同字符集的码是不一样的,所以需要各自的码表才能进行转换。譬如UTF-16转GBK,首先需要取到当前需要转换的字符的Unicode码,然后根据Unicode和GBK码表一一对应的关系(只有部分共同都有的字符才能在码表中查到),找到它对应的GBK码,然后用GBK的编码方式(双字节)进行编码

Unicode

  • Unicode:万国码,通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以
  • UTF-8:本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。
  • 对于一个操作系统或一个程序软件来说,其内部一般固定使用一种编码,如Java程序使用Unicode 字符集 UTF-16 BE 字符编码,在涉及到输入输出时就会存在一个编码转换问题,如读取文件,文件是以二进制的形式存在于硬盘上的,如何读取,必须假定一种字符编码来读取,如假定为GB2312编码,Java就会以GB2312编码的形式开始读取这个文件,转换为Java内部的编码形式 UTF-16 BE。所以并不是需要扫描多少遍,而是只需要在设计输入输出的时候转换一遍即可。读取到内存中的必然是系统内部使用的编码,想要显示这些文本,只需要根据编码换算出字符编号,然后调用字体文件信息即可。
    • golang内部的编码形式UTF-8。python:比Unicode早出现,所以python计算机内存中最早只支持ASCII码。

如何显示字符

引入

问:我知道ascii码2c 是“,”逗号,但是计算机是怎么知道它是“逗号”的?

简答:有时候不是会安装字体font么,里面就有对应的字型。要显卡渲染形成的。
大体过程是:字符编码(Unicode)→字体的形索引(Glyph ID)→字形轮廓→点阵图字形

屏幕是如何显示的

可以简单理解屏幕是由极多个像素点组成的,并简单理解一个像素点是由一个发光二极管来显示的。那么问题就回到了如何控制一个发光二极管的亮暗。作为上层应用,实际上不用太关心如何控制像素点的亮暗,因为这是由显示驱动电路来控制。而显示驱动电路的控制是由显示适配器(显卡)控制。

显卡的职能是将要显示的图形或文本转换成可以驱动显示器的电信号,它有三个重要的组成部分:

  • 显存:存储即将显示的数据,程序员将要显示的字符或图片送到缓存,后面的就是GPU和外围电路的工作了。
  • 显卡BIOS
  • GPU

字符显示

图形操作系统使用自己的字符呈现引擎(rendering engine),可以支持多个不同的字符集编码,这类代码页被称作ANSI代码页。

TrueType字体 及 FreeType软件开发库

TrueType字体不采用像素或其他不可缩放的方式来定义,而是一些通过数学公式(曲线的组合)。这些字形,类似于矢量图像,可以根据你需要的字体大小来生成像素图像。通过使用TrueType字体可以轻易呈现不同大小的字符符号并且没有任何质量损失。

FreeType是一个能够用于加载字体并将他们渲染到位图以及提供多种字体相关的操作的软件开发库。FreeType的真正吸引力在于它能够加载TrueType字体

那么字体是怎么被渲染的呢?从根本上来说,(除掉点阵字体)都是一些矢量图的集合。渲染字体,只是把矢量图画出来而已——说的轻松!

代码页CodePage

代码页是字符编码的别名,也称内码表,是特定语言的字符集的一张表。

内码

在计算机科学及相关领域当中,内码指的是“将信息编码后,透过某种方式存储在特定记忆设备时,设备内部的编码形式”。在不同的系统中,会有不同的内码。

在以往的英文系统中,内码为ASCII。 在繁体中文系统中,目前常用的内码为大五码。在简体中文系统中,内码则为国标码。

字符显示

首先是经过字符编解码,将硬盘中存储的有对应编码的文本文件进行加载,例如Java的文件IO,变成内存中的字符串对象,也就是符合本语言字符串存储特性的数据,(当然如果你愿意,也可以当做二进制读入,然后再手段转换编码,也是可以的),绘制时则首先调用对应的CodePage进行编码的索引查找,找到对应的字体字形索引,然后根据字形索引获取到字库中的数据,根据系统提供的绘制曲线绘制样条线的方法进行图形渲染,这样就能得到显示器上的图像了, 这里其实就是图形渲染。

图像的显示

例如照片,图片的每一个像素都可以理解成为三种不同颜色的组合。你只需要将每一个像素的RGB值送入显存,GPU会负责将其转换成电信号并输出给显示器。

参考

字符集:https://dailc.github.io/2017/05/03/char_charset_charEncoding.html

知乎:https://www.zhihu.com/question/296297701/answer/565941564

https://www.zhihu.com/question/24340504

how character display on screen:https://www.mmmmmcclxxvii.cn/2015/11/12/how-character-display-on-screen/

wiki:https://zh.wikipedia.org/wiki/