前言
计算机是美国人发明的,8个可以开合的晶体管来组合成不同的状态,0
代表关闭,1
表示的开启,那我们现实生活中的文字如何在计算机系统识别,实现人机交互呢。最开始0-32
作为控制码,后来美国人空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号。这样计算机就可以用不同字节来存储英语的文字了。美国人把他形成标准发布于是ASCII
(美国信息互换标准代码)出现了。随着计算机走向世界,这也成为世界标准。此时都是一个代码代表一个字符,256个codePoint
。随着各种语言文字符号需要出现在计算机中,256肯定远远不够,就汉字都有3000多常用的,扩充字符集编码势在必行。期间GBK2312、GBK18030陆续出现,但世界上还有很多少数名族语言,为了人类都可以用计算机,UNICODE
出现了。
Unicode
目前最新unicode支持十四万多字符。
代码点
Unicode中代码点范围0
到10FFFF
,也就是最大数值是1114111
,但并非所有代码点都分配给编码字符。
代码点数量
/**给定字符串开始结束范围,返回它的代码点个数。一个字符一个代码点。
*unicode字符串,每四位一个代码点,如果有高低位的就8位一个代码点。
*如小狗表情🐶(\uD83D\uDC36)就是一个代码点,它的高低位真正数值1F436
* 就代表这个代码点的索引值。
*/
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || beginIndex > endIndex ||
endIndex > length()) {
throw new IndexOutOfBoundsException();
}
if (isLatin1()) {
return endIndex - beginIndex;
}
return StringUTF16.codePointCount(value, beginIndex, endIndex);
}
代码点索引值
/**
* 根据代码单元在这串字符中的索引返回代码点在unicode表中的索引值
* 如小狗表情🐶(\uD83D\uDC36)就是一个代码点,它的高低位真正数值1F436
* 就代表这个代码点的索引值。根据它在在unicode码表的值,根据对应关系,找到计
* 算机系统字符表中对应的具体字符。
*/
public int codePointAt(int index) {
if (isLatin1()) {
checkIndex(index, value.length);
return value[index] & 0xff;
}
int length = value.length >> 1;
checkIndex(index, length);
return StringUTF16.codePointAt(value, index, length);
}
代码单元(Code Unit)
最小的数位组合,可以表示用于处理或交换的编码文本的单位。在 Unicode 标准中,UTF-8 编码格式采用 8 位编码单元,UTF-16 编码格式采用 16 位编码单元,UTF-32 编码格式采用 32 位编码单元。
BMP字符
位于 BMP(Basic Multilingual Plane,多语种基本面)代码点的 Unicode 编码字符。它的代码点在U+0000 到 U+FFFF 范围内的Unicode代码点。
代理半区
最初设计出Unicode设计者认为65536个字符足以表示完地球上所有字符,但是小语种的发现,这远远不够,语言也在自我发展比如emoj,那两字节已经不能满足,就和ASSCII
到unicode
一样,用三字节、四字节,自然增长。但这样就带来前期字符编码巨大空间浪费。而且读取时到底按几个字节读取?什么时候按两个字节,什么时候四个字节。代理高地区就出现了:
D800-DBFF
编码范围作为前两个字节(utf-16高半区),DC00-DFFF
作为后两个字节(utf-16低半区)组成一个四个字节表示的字符。
D800-D8FF有28个数,8-B有四个所以D800-DBFF一共有28x4=210个数。
低半区同样有210个数。所以高低代理半区一共可以表示220个代码点
类似于一维数组上升到二维了,同样长度表示的东西可是几何倍增长。
Unicode平面
最开始的unicode码21665536
个代码点可以看成是数轴上的点,不够数轴延长到17x216,每65536
个点为一个平面,一共17个平面。
第0平面称为BMP(Basic Multilingual Plane)平面,又称为基本多文种平面,第0平面外的平面统称为辅助平面,其范围为0000-FFFF。
- 第1辅助平面称为SMP(Supplementary Multilingual Plane)平面,又称为多文种补充平面,主要摆放拼音文字及符号,其范围为10000-1FFFF。
- 第2辅助平面称为SIP(Supplementary Ideographic Plane)平面,又称为表意文字补充平面,其范围为20000-2FFFF。
- 第3辅助平面称为TIP(Tertiary Ideographic Plane)平面,又称为表意文字第三平面,其范围为30000-3FFFF。
- 第4至13辅助平面尚未使用。
- 第14辅助平面称为SSP(Supplementary Special-purpose Plane)平面,又称为特殊用途补充平面,摆放语言标签(Language Tags)和异体字选择器(Variation Selectors),这些都是控制字符,其范围为E0000-EFFFF。
- 第15辅助平面为私人使用区:
补充私人使用区-A (F0000-FFFFF) Supplementary Private Use Area-A - 第16辅助平面为私人使用区:
补充私人使用区-B(100000-10FFFF)Supplementary Private Use Area-B
高低半区两点,它可以表示220个字符再加BMP
的216个(24x216高低半区
+216BMP
),就组成了17个平面。
/**根据代码点值,找具体字符
*/
public static char[] toChars(int codePoint) {
//是否第BMP第0平面
if (isBmpCodePoint(codePoint)) {
return new char[] { (char) codePoint };
//不是第BMP平面,就是高低位的
} else if (isValidCodePoint(codePoint)) {
char[] result = new char[2];
toSurrogates(codePoint, result, 0);
return result;
} else {
throw new IllegalArgumentException(
String.format("Not a valid Unicode code point: 0x%X", codePoint));
}
}
字符显示
所有图像的表示都是以像素为基础,无论是照片、浏览器图片、字符同样是一种图像。自然界中以光的形式被我看到的,都会被抽象到像素、位图概念。
光栅化渲染器
图像显示离不开渲染,对计算机显卡有了解的肯定知道如OpenGL,DirectX等。它们提供对外API,传入相关参数,调用函数即可达到渲染的目的。
它们就是光栅渲染器,一种嵌入Windows和Mac操作系统的软件。它收集有关显示的所有TrueType字体的大小、颜色、方向和位置的信息,并将这些信息转换为图形卡和显示器可以理解的位图。
字体
一个字体是共享一个共同的设计字符和符号的集合。字体资源文件实际上是一个只包含数据的DLL,没有代码。描述字体规格的标题和字形数据。由光栅渲染器知道它收集的是ttf、otf信息,这是不是很熟悉,字体文件格式?安装字体,就是把对应文字、表情信息存储到系统字体表
中。字体表是一个内部数组
,用于标识应用程序可用的所有非设备字体。应用程序可以通过调用EnumFontFamilies
或ChooseFont
函数来检索当前安装在设备上或存储在内部字体表中的字体名称。
每当应用程序调用添加和删除字体资源的函数时,它也应该调用SendMessage函数并向系统中的所有顶级窗口发送WM_FONTCHANGE消息。此消息通知其他应用程序内部字体表已被添加或删除字体的应用程序更改。
字体结构
字段名 | 描述 | 作用 |
---|---|---|
cmap | 字符代码到图元的映射 | 把字符代码映射为图元索引 |
loca | 位置表索引 | 把元索引转换为图元的位置 |
glyf | 图元数据 | 图元轮廓定义以及网格调整指令 |
这三个最主要结构,也是unicode如何找到具体字符。