文章 | 机核 GCORES ( ) • 2024-04-26 11:25
除了文字以外,人类表达信息的另外一个重要手段就是图案。图画比文字,更能在不同语言、不同种族间的人们之间传递信息。

如何在屏幕上显示“A”

我们使用的计算机,即便是最简单的“命令行”模式,实际上都是软件“画”出来的图案。如果没有图形能力,计算机就会是下图 1-13 所示的这种样子:
图1-13 纸孔带 图1-13 纸孔带
看到那两个程序员在盯着穿孔纸带看吗?感觉是不是很“杯具”?所以即便是我们认为已经很普通很简单的字符界面,背后也有一套完整的图形数字化机制在运作的。我们已经知道了字符 A在 ASCII 编码表中的代表数字是 65,那么计算机对于要把 65 这个数字所代表的图形“画”到屏幕上,还需要做什么工作?
最基本的就是要找到字符 A 的图形数据,也就是要知道如何用一系列的黑色像素点,在白色的背景上,拼出 A 的形状。我们可以放大一下,看看屏幕上的 A 实际上是怎么样的一个图形,如下图 1-14 所示。
图1-14 图形A 图1-14 图形A
这个图形,可以用一个 11 行 8 列的格子阵列来容纳,然后对于白色的格子用 0 表示,对于黑色的格子则用 1 表示。因此这个字符就可以按行分成 11 个数字的序列,而每个序列则从左到右的排列内容:
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 1 1 1 0 0 1 1 1
如果我们把数字排成一排,这将会是一个这样的序列:
000100000001000000011000001010000010100000100100001111000100010001000010010000111000111
虽然我们用肉眼看起来非常的晕,但是计算机却可以很轻松的处理这么长一串数字,它只需要按每 8 个数字一行的规则,把黑色或者白色的点画在屏幕上就可以了。除了 A 这个字符外,所有需要显示的字符,实际上都需要有类似上面的这串数字,作为描绘字符到屏幕上的数据的。这样一批代表字符“图形”的数字,往往被打包到一块,称为“点阵字库”。
同样的一个字符,可以具备多个不同的字体,只要我们用不同的点阵字库来负责“描绘”,就能得到不同的字体的显示,所以我们现在看到的,在屏幕上或者打印机打印出来的字符,都是由各种各样的点阵字库所控制的。
把要显示的图形,划分成很多小格子,然后对每个格子里面的内容用数字编码,然后把这些数字都串起来,是计算机记录图形最基本的方法。

绚烂的画面变成冗长的数字

对于仅仅有黑白两色的字符,可以用 0 和 1 的序列就可以完整的表达,但是如果是彩色的图案呢?其实方法也是非常类似的,我们可以看看下面这个例子,这是一个如下图 1-15 所示的老虎头。
图1-15 图1-15
如果我们把这个图形放大,就可以用一系列小方格来“近似”的描绘出这个图形,如下图 1-16 所示。
图1-16 放大后的老虎头 图1-16 放大后的老虎头
这个时候,我们只需要用点阵字库的方法,同样为每个点使用一个数字,来表示这个点的颜色,就可以了。当然因为我们用的是彩色图形,所以只用 0 和 1 是不足够的。具体的的编码规则其实很简单,就是把所有的颜色,先分解成红、绿、蓝“三原色”,然后根据这三种颜色的深浅程度各自分为 255 个等级,用 255 以内的数字来表示,这样一个颜色就会是“红色等级”“绿色等级”“蓝色等级”这样三个数字,这三个数字的最大值都是 255,放到一起相乘,就会是 16777215,也就是说每个点实际上可以显示 166777215 种颜色(实际上人眼很难辨认出 166777215 种颜色中的全部颜色)。这个是不是和 ASCII 编码表有点类似呢?是的,这只是一种为了用数字表示颜色而做的编码表。通过这个编码表,就可以把这个图案完全数字化成为一串由 166777215 以内的数字,所拼接起来的数字序列。
显然如果我们每个点都用 166777215 这么大的一个数字来表示,一幅图片将会要用很长很长的一串数字来表示。而从这副图片看,这里面大多数的数字都会是相同的,因此我们可以用一种叫“调色板”的方法,来大大的减少表示这幅图案的数字长度:
首先我们把这份图片里面用到的颜色都先抽取出来:比如黑色、白色、绿色、浅黄色、三种棕色、三种红色。然后我们用 0-9 为这 10 种颜色编号,并且把表示这 10 种颜色的数字,都先串起来,这样我们就得到了 10 个 16677721 5以内的数字——这 10 个数字就是这幅图片的调色板,包含了这幅图案的所有颜色信息。最后我们把代表整福图案的数字,全部都用“调色板”中颜色所对应的编号来代替,这样整个图案就会变成一串 0-9 之间的数字的序列,这串数字就大大的缩短了。最后我们把“调色板”和点阵图的数字拼到一起保存,就得到了最终图像的数据。如果需要显示这串数字所代表的图案,只需要先读出“调色板”,然后再读出每个点的数字,去“调色板”那里查找一下,获得最终的颜色数据,根据这个颜色数据去显示对应的颜色(这环节显示卡的驱动程序会完成),就能还原这幅图案了。
上面所说的显示彩色图形的方法,其实只是显示黑白字符的一种扩展,都是用“点阵”作为基础的描述方式的方法,这种方法有一个专用的名字叫“位图”。然而除了位图方式来表达图形,还有另外一种叫“矢量图”的方式。矢量图不去把图形分割成很多个小格子来描述,而是把图形中的线条都描述成函数曲线,然后记录这些代表这些函数的数字,来表达图形。这种方法的好处是图片无论如何放大,都一定不会失真,因为函数曲线不会因为放大而变化,缺点就是,如果要把图片用函数来编码,需要很复杂的计算,所以现实和保持这些图片比较耗费 CPU 的运算时间。互联网上曾经流行的 FLASH 图画,很多就是用矢量图方式来制作的。

其他的信息是如何用数字来记录的

前面我们探讨了如何用数字来表示文字和图形,这两种不同的信息的数字化方法中,其实是有一些共同点的:
把信息分解成很多单元。数字化文字信息的时候,就是按照每个字符进行分解,把一篇文章分解成很多个字符,每个字符作为一个信息单元。处理图形的时候,则是按照图形的平面,分解成很多个小格子,每个格子作为一个信息单元。
对每个单元的所有可能情况,建立一个编码表。对于文字信息,每个单元的可能情况,就是所有可能出现的字符,所以需要为每个字都建立一个编号,从而形成文字的编码表。而对于图形,每个单元的可能情况,则是每个格子可能显示的所有颜色,所以需要为每个颜色都建立一个编号,于是我们就按照三原色分解,并且把每种原色划分 255 个深浅程度来编码。
根据分解的单元和编码表,把信息变成一长串的数字。文字就是把按编码表生产的数字组合起来,表示一系列的文字。图形则是把代表各种颜色的数字组合起来,表示一幅图案。
以上三个共通的做法,除了用来表达文字和图形,同样也可以用来表达很多其他的信息,比如声音,我们可以把声音按时间分解成单元,然后对每个单位时间里的声音,按照其频率和音量编码。最后把一个声音变成一串以频率、音量所编码的数字。对于动画,也可以按时间分解成一帧帧的画面,每幅画面再以数字编码,这样由多组表示画面的数字所串接的序列,就可以用来表示动画了,GIF 格式的动画就是用这种方式记录的。如果你要记录的是类似电话本之类的数据,则一样是先把电话本的条目先分解,然后再把每个条目分解成“名字”、“电话号码”两个部分,最后以文字编码表来编码“名字”和“电话号码”,最后把这些编码后的数字一起串接起来,形成一个完整的电话本。
任何的信息,只要有办法进行分解,编码,就能变成数字放到计算机里处理。所以现代的计算机几乎可以处理任何我们能接触到的信息。而指挥计算机去“解码”(把数字变成信息)和“编码”(把信息变成数字)的方法,正是计算机软件最常见的工作。

贻害甚广的“二进制文件”

我们时常会这样形容一个文件:“这是一个文本文件,这是一个图片文件,这是一个 Word 文件……”,但是当我们无法说出一个文件的类型的时候,我们就会说:“这是一个二进制文件”,然而,这个说法有几个严重的概念错误,从而阻碍了我们对于解决文件格式所能做出的反应。
所有文件都是二进制的,但没有一种叫“二进制”的编码格式。二进制是计算机用来记录数字的一种方式,但是这种数字的记录,必定要有其所代表的实际含义,才真正的有用,所以一定要有对应实际信息的编码格式。我们如果说一个文件是“二进制”的,实际上和没有说“二进制”这个词是一样的。或者这么说仅仅是表达“未知编码格式”文件的意思,但是这样会误导听到这个说法的人,让他试图去寻找一种“打开”二进制文件的方法。事实上也真的有打开“二进制”文件的软件,但是这种软件一般来说没有太大的实用意义,因为如果让你看到一串不明含义的数字,又能做什么呢?
每个文件都有它的编码格式,就算你不知道,它还是按自己的格式编码的。我们往往因为认为一个文件是“二进制”的,就怀疑这个文件是无法被解读的。但是实际上任何文件都一定有解读的方法,只是你还没知道他的格式,或者没有对于的解读软件而已。就如同你没有安装 Adobe PDF Reader 软件,那些 PDF 格式的文件,对于你来说就是“二进制”格式一样,如果你装了这个软件,这个文件就变成一种可用的格式了。因此你所认为的“二进制”实际上也是毫无意义的。
任何格式的文件,本质上都是数字,并不一定是要看成是二进制的。虽然计算机底层确实是用二进制的方式来记录数字的,但是从软件层面看,任何的数字,都可以被编码成任何一种进制,而在实际的软件开发中,程序员们处理数据最常用的往往不是二进制,而是 16 进制。原因是对比二进制,用 16 进制来写一个数字显然简短的多;对比十进制,16 进制又能更容易的换算成二进制数字,用来控制计算机底层。除了 16 进制,程序员们有时候还会用 8 进制,甚至别的一些数学进制。所以二进制本身并不能说是软件层面的唯一进制。用这个说法来表示文件格式,也是不尽准确的。
文件名后缀仅仅是文件格式的提示,同样一种编码格式的文件可以有不同的后缀。比如说一个图片文件可以叫 a.jpg,也可以叫 a.jpeg,只要显示这个文件的程序,认识这两个后缀,并且都按 JPEG 的解码格式来显示这个图片,就一样能显示成功。然而如果你把一个 wav 格式的文件后缀改成 jpg,你也可能可以打开这个文件,但是一定看不到任何有意义的图案。就好象你把一个图形文件后缀改成 txt,就会得到一串文字“乱码”一样。
文件格式的含义是丰富和多层次的,并不是每个文件只能有一种“格式”。比如我们常见的网页文件 xxx.html,这种文件同时是文本文件和网页文件。你可以用“记事本”或者 Word 软件来打开,也可以用浏览器来打开。两种打开软件所显示的内容会完全不一样。同样的例子还有存放JavaScript 的 .js 文件、XML 文件等等。
希望我们在了解了计算机如何用数字来表达信息之后,我们能够理解计算机中各种文件格式的含义,而不会再被各种“格式”的说法弄的头晕脑胀。——一切都是数字,用数字表达的信息。