計算機系統是如何顯示一個字元的?

始終沒明白字符集/字元編碼/區位碼/內碼/字體等等這一系列的概念。不要講歷史,因為我已經看得夠多了,請直接用某一特定操作系統講機制,從鍵盤按下一個按鍵開始,各個相關部分是怎麼工作的,如unicode在什麼時候起什麼作用,freetype在什麼時候起什麼作用,計算機要在哪裡查找什麼信息。越細緻越好。


我來就 Linux + Xorg 系統回答一下吧。我不知道,也沒辦法知道 Windows 上的情況是怎麼樣的。我的回答在細節方面可能不會太詳細,一方面是因為細節並不影響理解,另一方面也是因為我對一些細節的了解也不是那麼深。

從按鍵到字元在屏幕上顯示,其實是一個很複雜的過程……我粗略估計了一下,這個過程中執行的指令,對應到源代碼,可能要超過10萬行。

那,就從按下鍵開始講起吧。當你按下鍵後,一個電信號從鍵盤通過 USB 介面或者 PS/2 介面送到了匯流排,然後引起了一個中斷。如果是在老機子上,管理中斷的可能是8259A 晶元,新的機子上則可能是 APIC 。CPU 收到中斷之後,會暫停當前的程序的執行,調用事先設定好的中斷處理過程。Linux系統的中斷處理一般分為兩個部分,Top half 和 bottom half。其中直接響應中斷的是 top half,因為系統不能在中斷處理過程中停太久,所以 top half 只是記錄中斷的發生,真正中斷處理過程是在 bottom half 中完成的。

bottom half 在 top half 之後執行,具體執行取決於進程調度。在 bottom half 中內核會找來負責的驅動,比如說 USB HID 驅動,處理鍵盤輸入。這個鍵盤輸入會反映在 /dev 下面某一個字元設備中,比如說 /dev/input/event0 。Xorg 為了獲取鍵盤輸入,會對這個設備進行 select() 。select 這個系統調用會將進程 block ,直到有可用輸入。在內核中的反應就是,內核會將進程的狀態設為 TASK_INTERRUPTIBLE ,然後調用 schedule() 將運行權讓給別的進程。當鍵盤輸入到來的時候,內核會查看是否有進程正在 select /dev/input/event0 這個設備,如果有,內核會將對應的進程從select 中喚醒,以便處理這個輸入。

於是Xorg就被喚醒了,我們也終於從 kernel space 里逃了出來,來到了 user space 。Xorg 會從 /dev/input/event0 讀出一組數據。這組數據的定義如下:

struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
unsigned int value;
};

time 是事件發生的時間,type 是事件類型,對應鍵盤就是 EV_KEY ,code 在這種情況下是一個 key code,value 則代表是按下鍵還是放開鍵。

Xorg 在讀到事件之後,還需要將來自 kernel 的 key code 翻譯成 Xorg 自己的 key code 。完成這個的是 libxkb ,鍵盤布局也是在這個階段起作用的。然後,Xorg 會找出當前焦點所在的窗口,然後將事件發給它——這是簡單的情況。如果你運行著一個窗口管理器的話,這個事件很可能還需要在窗口管理器中過一遍,並且由窗口管理器決定是否要發給窗口。如果接受按鍵的程序支持輸入法,這個按鍵可能還要在輸入法里走一圈。這個過程中的事件發送/接受都是通過 socket ,使用的協議是 Xorg 的協議,使用的庫(歸根結底)一般是 xlib 或者 libxcb 。

(補充一段關於編碼的)

應用程序在接到 Xorg 發來的事件之後,就會對事件作出反應。比如說一個文本編輯器,在接到按下『X』的事件之後,需要在文件中插入一個『X』。那麼這個『X』是怎樣在文件中表示的呢?你應該知道,內存也好硬碟也好,是用二進位來保存數據的。要表示一個『X』,我們必須先給它分配一個對應的數字。幸好,早在近60年前,就有人幫我們把這件事辦好了。這就是所謂的 ASCII 碼。『X』在其中對應的數字是120。

但是,如果我通過我的輸入法,輸入了一個中文字的話怎麼辦?當然,我們還是用一樣的辦法,給每個中文字一個編號。這個編號,在中國的國標碼中被稱作區位碼,在 unicode 中被稱作一個code point。比如說,國標碼給「啊」字編的號就是1601。

雖然現在我們給中文字也編上了號,我們還不知道應該怎麼把它存到文件中去。你可能會覺得這很簡單,直接把編號存進去不就是了?比如1601就存兩個位元組0x06和0x41。但是這會造成一個問題。假如你的文本編輯器同時支持ASCII碼和我們設計的這個中文編碼,它要怎樣才能知道某個文件是按什麼編碼的?0x16和0x41在 ASCII 中都是合法編碼,這樣就會造成一個文件存在歧義。不過幸好,ASCII 只使用了0~127來編碼字元,所以只要我們只用128~255,就可以和ASCII區分開來。比如說,我們可以將編號按7位二進位分段,然後在第一位添上一個1:

1601 -&> 11001000001 -&> 0001100/1000001 -&> 10001100 11000001 -&> 0x8c 0xc1

在國標碼里,這個編碼後的結果就是這個字元的內碼,注意內碼和區位碼的區別。而 unicode 和 UTF8,UTF16 也是類似。unicode 是一種給字元編號的方法,UTF8、UTF16則是把這個編號記錄到文件里的方法。

到這裡,我們的旅程才完成了一半。而且是比較簡單的一半。

現在你的輸入已經跑完前半程,終於到達應用程序了,不過等等——這個程序,是什麼程序?是一個終端虛擬器,文本編輯器,還是chrome裡頭的某個文本框?取決於對這個問題的回答,後半程的路線會非常不一樣。

假如說這個程序是 xterm ,它會通過 X core font API ,將這個字元直接送給 Xorg ,由 Xorg 來完成字體渲染(當然現在 xterm 也支持 libXft 了,不過先不管這個)。Xorg 拿到應用程序送來的請求之後,會在字體中檢索每個字對應的字形,然後渲染出來。這個檢索過程中用到的索引,就是我們之前給字元編上的號。如果要指定字體,需要向Xorg提供一個長得像這樣:「-adobe-times-medium-r-normal--12-120-75-75-p-64-iso8859-1」 的字元串來指定字體。當然,這樣渲染出來的字體不會很好看,像這樣:

(我不是很清楚 X core font 是否有反鋸齒一類的能力,應該是沒有,歡迎糾正。)

如果這個應用程序是 gedit,那麼它就會選擇自己渲染字體,然後將渲染結果直接發給 Xorg,由 Xorg 呈現。在 Linux 下,你想用這種方式渲染字體,有兩個庫你是逃不過的:fontconfig 和 FreeType2 。大致上來說,fontconfig 讓你能通過一個字體名找到對應的字體,FreeType2 則進行具體的渲染。

那麼字體是怎麼被渲染的呢?不管你用的字體是TrueType還是OpenType還是什麼格式,從根本上來說,(除掉點陣字體)都是一些矢量圖的集合。渲染字體,只是把矢量圖畫出來而已——說的輕鬆!

渲染文字是個複雜的工作,我也不能說我對此了解很深,只能大致講講。

字體如果是顯示在屏幕上,因為屏幕的dpi和紙張沒法比,所以必須反鋸齒,否則就會這樣:

這只是通過灰度進行反鋸齒,我們還可以做的更好。如果你是在使用LCD顯示器的話,你屏幕上的像素,長的可能是這個樣子的(圖片來源,wikipedia):

灰度反鋸齒只是在整個像素尺度上進行的,但是既然像素中還可以分為更小的成分,那麼我們為什麼不通過這更小的單位進行反鋸齒?這種方法就叫做 Subpixel Rendering,或者一個更被人熟知的叫法:ClearType。下面是兩種反鋸齒的比較,圖還是來自 Wiki :

可以看到 subpixel 渲染的結果會讓邊緣帶一點色彩。一般來說 subpixel 渲染可以字體看起來更清晰一點,你可在自己的系統上開啟/關閉 subpixel redenering 比較一下。

人們為了讓字體在屏幕上看起來能清晰一點,真是用盡了心思。因為反鋸齒會讓字體的邊緣變得模糊,讓人覺得字體看起來不是那麼「銳利」,人們又想出來要給字體做Hinting(不知道如何翻譯)。Hinting將字體微調,讓橫和豎都對齊像素,來盡量減少反鋸齒帶來的模糊。下面是個(應該一下就能看明白的)例子(圖還是來自 Wiki):

Hinting 的具體實現是很複雜的。因為不同字體需要不同的 Hinting 對策,所以字體中會存一些 Hinting 數據來指導 Hinting。而這些數據,每一個都是一個用特定彙編語言寫成的小程序!FreeType2中則包含了一個虛擬機,來運行這些程序,來將字體對齊到像素。

當然也有些字體會不帶 Hinting 數據,但是 FreeType2 還是可以進行 Hinting ,也就是 Auto-hinting。具體的演算法我就不清楚了。

值得一提的是,因為 Apple 拿著很多有關 Hinting 的專利,FreeType2 默認是關閉 Hinting 的,而只使用 Auto-hinting 。直到2011年這些專利全都過期之後,FreeType2才默認支持 Hinting 。

好了,不管你是讓Xorg進行字體渲染,還是讓應用程序自己進行渲染,最後的結果都是一小塊比特圖。我們要怎麼把這塊圖顯示在屏幕上呢?

Xorg 之中,有一個部件叫做 EXA,是用來提供硬體加速的2D渲染的。EXA的歷史很長,最早可以追溯到1996年 Harm Hanemaayer 給 Xorg 實現的 XAA。XAA 後來被 EXA 所接替。現在 EXA 又開始要被 UXA 取代。這些部件雖然都有同樣的目的,但是實現都有所不同。具體的區別在這裡就不展開了。總的來說,他們的功能是,在顯卡驅動的幫助下,將二維圖形顯示在屏幕上。

到這裡,好像就結束了。但其實還沒有。2011年的光棍節,Glamor誕生了。Glamor試圖將2D的渲染也用 OpenGL 來完成。一張二維圖,大概會被轉變成 OpenGL 的貼圖,然後渲染在屏幕上。目前這個項目還在開發中,性能(在大部分情況下)還不如EXA。

如果所有的渲染都由 OpenGL 也就罷了。如果你還在用 EXA,但是你的某個程序(比如說Chrome)非想用 OpenGL 來顯示文字怎麼辦?顯然的辦法可以是讓程序把所有的 OpenGL 請求都發給 Xorg,讓 Xorg 代理。這種方法就叫做間接渲染(Indirect rendering),Xorg 的一個擴展:AIGLX,就是用來完成這個工作的。

有一個額外的中介大概是會影響性能。雖然我沒有具體的數據來證明這一點,不過既然後來 DRI 的出現大概是一個佐證。DRI 是 Direct Rendering Infrastructure 的縮寫,分為兩個部分,分別存在於內核與 Xorg 中。內核的部分叫做 DRM,用來協調多個程序對 GPU 的訪問;Xorg 的部分則是一個驅動,也叫 DRI 。程序想要使用 OpenGL ,先要通過 DRI 向 Xorg 申請一塊緩衝區,然後通過 DRM 訪問 GPU 向這個緩衝區進行渲染。當然這些事不會直接讓程序去做,都是通過 Mesa 這個 GL 庫完成的。

到這裡,還是沒有結束。

萬一你不幸有個帶 NVIDIA? Optimus? 的本子怎麼辦?使用 Optimus 技術的獨顯不會直接和顯示器連接,所以想要直接讓獨顯渲染是不行的。現有的解決方案是 BumbleBee,就是之前那個刪了用戶 /usr 目錄,出了點小名的那個。BumbleBee 的做法是再啟動一個獨立的、跑在獨顯上的 Xorg,然後用它進行渲染。但是獨顯沒法輸出到屏幕,怎麼辦呢——只好把渲染結果在兩個 Xorg 之間傳來傳去了。BumbleBee 用了 VirtualGL 來完成這個任務。

另外一個還在開發中的解決方案叫做 Prime(開發者就是喜歡和變形金剛過不去)。Prime 利用的是一個還在開發中的內核功能:DMA-BUF,讓兩個硬體共享一塊內存區域。我不清楚具體的原理,不過大概是讓一塊顯卡渲染完之後,DMA 寫到內存里,再讓連接顯示器的顯卡 DMA 讀出,輸出到屏幕吧。

用來 Optimus 以後,感覺本來的長跑,直接就變成了馬拉松……

以上差不多就是全部了。不知道你們是不是還有興趣,要是把場景換成 Wayland ,還有很多可以講。


大體過程是:字元編碼(Unicode)→字體的字形索引(Glyph ID)→字形輪廓→點陣圖字形

具體細節的話去看 Freetype 源碼好了


正巧,今天下午我也遇到了難纏的編碼問題,既然前面烏鴉朋友已經介紹的非常詳細的計算機底層原理,我就從另一個側面談談計算機編碼及亂碼問題產生的根源。今天寫了這樣一段文章,就拿出來和大家分享。

從編碼問題的產生說起

我們知道,計算機是美國人發明的,人家的英語體系總從來就只有26個英文字母和一些數字、特殊字元等,為了儲存文字信息,於是使用了最早的ascii碼進行字元編碼。而後來由於計算機的普及,多國語言文字變得重要起來,於是多語言的特性成為了計算機的必備,各國進行各國的國家標準編碼,中國的便是GB2312(1980年),而後1995年又頒布了《漢字編碼擴展規範》(GBK),GBK與GB2312相兼容,但又增加了一些兼容漢字,方便了和Big5碼等進行轉換。這套GBK編碼,逐漸成為了中國計算機的主流編碼。


Unicode字符集和UTF-8編碼

隨著計算機的發展,往往一款軟體不但要兼容一個國家的語言,還要兼容許多國家的語言,尤其是亞洲國家中日韓三國,光中文常用字元就有7000,所以要解決這麼多文字的編碼問題,就需要用更多規模的表示,Unicode是一個巨大的字符集,囊括了世界各地的語言,這樣編碼就更為統一和方便了。但Unicode並沒有規定這些字元具體應該怎麼樣在計算機中存儲,雖然字符集是全的,但計算機中要兼顧效率和方便等問題,UCS-2是其中的一種常用方案,採用兩個位元組來編碼一個字元,這和ascii碼不兼容,而且還有一個大問題,UCS-2並不能表示全部的漢字,漢字的簡繁體加起來總共有六七萬,UCS-2隻有65536個編碼,根本存不下,所以只收入了大部分常用字。也有表示所有漢字的方案UCS-4,不過4個位元組用來存儲漢字,效率就較為低下。

UTF是「UCS Transformation Format」的縮寫,是Unicode字符集的一類高效實現方式。

UTF-8是我個人比較喜歡的一種編碼方式,它是一種針對Unicode的可變長度字元編碼,又稱為萬國碼。它使用1-6個位元組進行編碼,最前面128個編碼內容和ascii碼兼容,所以我們用UTF-8編寫純英文文本是和ascii碼幾乎一樣的。(注意我說的是幾乎)。

如果UNICODE字元由2個位元組表示,則編碼成UTF-8很可能需要3個位元組。而如果UNICODE字元由4個位元組表示,則編碼成UTF-8可能需要6個位元組。用4個或6個位元組去編碼一個UNICODE字元可能太多了,但這樣的UNICODE字元往往是生僻字,極為少見。
這種編碼的思想和哈夫曼編碼是類似的,將高頻字元縮短,低頻字元變長,使得整體的編碼效率更優。

我以前有段時間,就經常將Unicode和UTF-8搞混了,Unicode是字符集,網上不嚴格的情況也指Unicode字符集的常用編碼UCS-2,也就是用兩個位元組編碼的Unicode碼。

一些常見系統的編碼:
VC 6.0 Ascii碼
VS2008 - 2013 UCS-2(開啟Unicode後)
Windows中文版 GBK
Linux(andorid) UTF-8
Mac OX UTF-8
JAVA UCS-2
Python2 ascii (byte)
Python3 UCS-2
注:操作系統所述都是默認編碼,這三種主流操作系統的系統編碼都是可以更改的。

MBCS(Multi-Byte Character Set)和內碼錶(codepage)

再介紹兩個字符集中較為深入的概念,MBCS和CodePage。
MBCS(Multi-Byte Chactacter System,即多位元組字元系統),是所有多位元組編碼方案的總稱,MBCS 編程主要用於為國際市場編寫的應用程序。由於往往是針對一國市場只有一種文字,那麼為了節約資源,往往將這些文字用雙位元組或盡量少的位元組的方式進行保存。

因為這些雙位元組文字和ANSI是混和在一起的,為了加以區別,Windows將這些字元的最高位置為1(即這些雙位元組文字的每個位元組都&>=127),所以這種表示法可以表示 127x127 約一萬多種非ANSI文字 ,其本上可以表示任何一種語言的常用文字了。於是,Windows為每一個區域版本,都制定了分別獨立的文字編碼,這就是MBCS(多位元組碼)。

而這些分頁後的編碼方式,都被保存成了不同的CodePage(內碼錶,這裡內碼的意思是機器內部編碼,相對於外碼,外部輸入文字用的編碼,例如拼音、五筆、鄭碼等),例如中文就是大家熟知的CP936。要注意,這種編碼方式是早期windows獨有的,由於使用較早,應用也十分廣泛,而CP936和GB2312-80在編碼上則是幾乎一樣的(此處見Wiki百科——漢字內碼擴展規範),後來擴展GBK後,CP936也進行了同樣的擴展。

此技術的使用最早追溯到MS-DOS3.3(1987年4月發行)向IBMPC用戶引進了內碼錶的概念,Windows也使用此概念。

這是微軟官網上給的10081頁的CodePage

內碼錶成為了系統進行多語言編碼及轉換的重要工具。當然,Unicode碼也被收入CodePage中。

說白了,MBCS和CodePage就是計算機解決多位元組編碼問題的通用手段,各種區域編碼可以在其中找到對應編碼的映射的,Unicode和UTF-8也是可以在其中找到對應的映射的。

常見的CodePage
932 —日文
936 —簡體中文(GBK)
949 —韓文
950 —繁體中文(大五碼)
1200 —UCS-2LE Unicode 小端序
1201 —UCS-2BE Unicode 大端序
1252 —西歐拉丁字母ISO-8859-1.
65000 — UTF-7 Unicode
65001 — UTF-8 Unicode


計算機是如何顯示文字的呢?

計算機要對文字進行存儲後就需要顯示出來,而我們的液晶屏都是一個個的像素點組成的,這就必須要對文字進行渲染繪製,發送到顯卡中進行柵格化和顯示等操作。
Dos下最簡單,利用主板BIOS就能對ascii碼進行點陣化輸出。簡單的我們就不再多談,windows下是如何對文字進行繪製顯示的呢?

字型檔

我們都知道,顯示字體除了要有文字的編碼,還需要有顯示用的字的樣式,這就是 字型檔,windows下的fonts文件夾大家應該都十分熟悉,更改或刪除字型檔就是就是文件的移動而已。而字型檔實際上也有不同的種類的,構建原理也不都相同。

最早的字型檔是點陣字型檔,這種字型檔看起來和黑白圖片貌似沒有什麼大區別,就是記錄像素是黑還是白,我們用windows自帶的字型檔編輯程序,就可以處理這種字型檔。
這種字型檔的缺點也是顯而易見的,首先是縮放不易,在小字體和大字體顯示時都容易失真走樣,而且佔用空間較大。

矢量輪廓字型檔,這種字型檔是用的矢量圖原理進行存儲的,將外部邊界抽象成數學上的矢量線段,可以方便的縮放旋轉等操作。缺點則是連續性不好,放大後就變出行了摺痕,效果不夠理想。

曲線輪廓字型檔,這是通過直線和曲線段共同構造文字的方法,往往使用Bezier曲線對輪廓進行擬合,效果非常好,字體平滑美工,但惟獨就是計算較為費時間。

TrueType字形技術
TrueType採用幾何學中二次B樣條曲線及直線來描述字體的外形輪廓。由一些數學演算法進行對應大小字體的生成,無論放大或縮小,字元總是光滑的。
TrueType字體與PostScript字體、OpenType字體是主要的三種計算機矢量字體(又稱輪廓字體、描邊字體),後綴.ttf。
雖然計算較快,但相比於PostScript字體,質量要差一些,特別是文字太小時,不夠清晰。
所以字型檔一般會對小字體和常用列印字型大小製作對應的點陣字型檔,保證其精度,其他情況則使用TrueType字體。

WOFF–WebOpen Font Format (.woff)
WOFF(Web開發字體格式)是一種專門為了Web而設計的字體格式標準,實際上是對於TrueType/OpenType等字體格式的封裝,每個字體文件中含有字體以及針對字體的元數據(Metadata),字體文件被壓縮,以便於網路傳輸。

其實大家就會發現了,網路上很火的圖標字體,實際上就是根據最基礎的字型檔技術生成出來的。

字體的顯示流程

介紹到這裡,大家應該對整個字體的繪製過程有個整體的認識了,首先是經過字元編解碼,將硬碟中存儲的有對應編碼的文本文件進行載入,例如Java的文件IO,變成內存中的字元串對象,也就是符合本語言字元串存儲特性的數據,(當然如果你願意,也可以當做二進位讀入,然後再手段轉換編碼,也是可以的),繪製時則首先調用對應的CodePage進行編碼的索引查找,找到對應的字體字形索引,然後根據字形索引獲取到字型檔中的數據,根據系統提供的繪製曲線繪製樣條線的方法進行圖形渲染,這樣就能得到顯示器上的圖像了。而更高級的就是對字體進行反走樣,銳化,等更為細節的操作了。

本文好多內容是基於我自己的理解寫成,如有疏漏錯誤,還請指正。


想像一下你現在在記事本裡面打字(只考慮英文輸入),然後按照我下面說的來思考:
1.鍵盤上的每個鍵都有一個編號,比如按鍵A用編號VK_A來表示。CapsLock用VK_Cap表示,
Shift用VK_Shift來表示。
2.大小寫的切換。記事本程序內部(也有可能是操作系統就記錄了)需要一個標記位來記錄現在是大寫還是小寫。假設這個標記是Cap_Flag,默認是Cap_Flag為false,按一下就變成true,再按一下就變成false。
3.Shift鍵。你按下VK_A鍵的時候,程序會判斷VK_Shift是不是也被按下去了,還有當前Cap_Flag的狀態。根據這三者來確定你現在輸入的是大寫A還是小寫a。
4.字元的存儲。純英文字元很少,不超過256個。其實主要就是大寫A到Z,小寫a到z,數字0到9.其他的比如空格(Space),製表符(Tab),換行符(Enter),再具體的就不細說的。總之每個字元有一個數字來存儲它。不同的字符集存儲字元的時候可能不同,有的能存的多,有的能存的少,有的幾種字符集有重疊部分,有的不重疊。
5.字體。每個字元長什麼樣,這叫做字體。就和書法一樣,有正楷,有草書,隸書等等。字元的字體常用的比如宋體,黑體,仿宋,英文的比如Times new Roman.
6.每個字元的樣子是怎麼存儲的。每種字體應該要存儲所有字元的樣子,不過也許有些字元根本就沒存,顯示的時候可能就是一個方框。字體可能用像素矩陣存儲,也許用矢量圖存儲。所謂像素矩陣就好比活字印刷術的活字吧(好比印章一樣),那字只能那麼大,放大縮小都可能不清晰。矢量圖就是一些線條,粗多少,長多少,有一些基本元素組成,等確定了字要以多大顯示之後再柵格化到像素上。


要想深刻的理解計算機如何顯示字元,我推薦的步驟如下:
學習使用最簡單的51單片機配合一塊最簡單的12864液晶屏顯示一個字元。
如果嫌麻煩,端詳12864液晶屏幕,仔細觀察上邊的小方塊,心中想一個字元,腦補小方塊被點亮的情景,就理解了字元是如何顯示出來的。


先挖個坑慢慢填。
鑒於本人搞軟體出身,一下內容中硬體和驅動相關部分基本不談,而以軟體為主。
先來段廢話:字元的輸入和輸出是有UI的計算機的兩項基本功能,這兩塊的水很深,簡單的一個高中生可以很快寫出來,稍複雜點的足以解決一個程序員團隊的溫飽。

先看流程
最簡單字元輸入的過程:a輸入設備產生輸入信號後,b根據鍵盤的布局產生基礎字元,c根據多個基礎字元和轉換表產生中間字元並由用戶選擇,(d複雜點的話中間字元再根據輸入和字典產生最終字元),e然後將中間字元(或最終字元)作為結果傳給客戶程序。
實例:
a按下鍵盤從下往上第5行左側第二個鍵,
b根據鍵盤布局不同產生基礎字元如q,a,z此處以q為例
c查表產生中間字元列表奇,起,氣等,假設用戶選擇氣
d查字典得到氣氛,氣球等候選詞,用戶再選澤氣氛
e用戶將最終詞氣氛傳給客戶程序。用戶程序就得到氣氛一個串

文字輸出的簡單過程
1對用戶傳入一個字元串進行編碼轉換
2.對字元串進行編碼重整
3.根據字元屬性分隔
4 根據字型檔信息獲得字元和字體的度量信息列表
5根據度量信息和顯示寬度將文字分為多行
6根據度量信息排布字形計算每個字形的位置
7按照字形位置將字形繪製到畫布上
今夜到此為止,明日繼續


計算機顯示圖像和顯示字體本質上有什麼區別嗎?


在UNIX終端上和DOS里 , 字元是終端或顯卡(使用內置字型檔)繪製的,不但跟unicode和freetype什麼的沒有任何關係,而且跟操作系統都沒有關係。
印表機也是如此:當你把一個文本文件直接發送給印表機,印表機使用內置的字型檔繪製每個文字和符號


推薦閱讀:

GB2312、GBK、GB18030 這幾種字符集的主要區別是什麼?
為什麼有時候"元"(yuan)字會變成"刀"(dao)字?
顏文字使用的都是哪些編碼?裡面都有哪些國家的文字?

TAG:操作系統 | Unicode統一碼 | 字元編碼 | 計算機科學 | 字符集 |