1. 程式人生 > >絕對詳解PHP 的imageTtfText()函式

絕對詳解PHP 的imageTtfText()函式

圖片處理,是許多程式的功能之一;而文字渲染則是繪圖的基本組成部分。PHP通過很多擴充套件庫來支援圖片的處理,最常用的還是GD庫,通過一系列imagexxx()函式來提供繪圖功能。本文專注於非常細小的一點:繪製文字。熟悉Win32的人都知道,TextOut()就可以輕鬆顯示任何文字了,然而到了PHP的世界裡,有些事情並不輕鬆。
1 詳細解釋imageTtfText()函式

對於PHP繪圖初學者,首先遇到的一個問題就是,imageString()這個函式並不支援漢字的繪製。這往往會給入門者當頭一棒,不過不要著急,因為還有一個imageTtfText()函式,這個函式能繪製UTF-8編碼的字串,當然可以繪製漢字了。然而使用它並不十分簡單。先來看看其原型宣告:


一共有8個引數,缺一不可,而且官方文件這些引數的解釋並不透徹,這裡筆者盡力做更詳細清晰的解釋:
(1)$image 這個是畫布資源,無需再解釋;
(2)$size,官方文件的解釋是,字型大小,其長度單位依賴於GD庫的版本,對於GD1來說是畫素,對於GD2來說是磅(point)。現在一般都是GD2了,那麼這個磅究竟是什麼意思呢?這涉及到字型設計的基本知識。

簡單來說,磅是一個長度度量單位,如果把一英寸等分成72份,每一份就是1磅。這裡需要強調的是,磅是個絕對物理單位,與顯示裝置無關。

而畫素呢?畫素沒有固定的大小,而是與解析度相關,高解析度的顯示器畫素就很小,如iphone視網膜屏上一個畫素的大小要比普通LCD顯示器的畫素小很多。然而有些東西是不存在解析度這個概念的,如單純的點陣圖圖片,它的最小組成部分就是畫素,本身也是通過每個畫素的顏色值來定義的。把同樣的圖片顯示在不同解析度的顯示器上,最終呈現出的大小是不同的。

操作點陣圖時,以畫素位單位最精確合理,那麼使用GD2庫的時候,如何繪製大小為20畫素的字呢?也就是多少磅才能等於20個畫素呢?這必須通過解析度才能計算出來,而問題是點陣圖本身並沒有解析度的概念。

現在把問題返回來,如果給定$size=20磅,那麼imageTtfText()繪製完成時,究竟會佔用多少畫素。無論如何,imageTtfText()最終還是要把文字繪製落實到具體的點陣圖畫素上。

1磅 = PPI/72 個畫素

這個問題確實非常棘手,此函式內部必然會使用某個解析度PPI來計算被渲染的畫素區域。而GD2庫卻沒有提供任何讓使用者設定或者讀取這個解析度的方法。那麼,我們只能動手測試了。使用不同的磅值繪製文字,然後測量文字佔據的畫素,通過公式:
PPI = (72*畫素數)/磅值。實驗得出的結論是:
1磅==>4畫素, PPI=288
2磅==>5畫素, PPI=180
3磅==>7畫素, PPI=168
4磅==>8畫素, PPI=144
5磅==>9畫素, PPI=129.6
6磅==>10畫素, PPI=120
7磅==>11畫素, PPI=113.14285714286
8磅==>12畫素, PPI=108
9磅==>14畫素, PPI=112
10磅==>15畫素, PPI=108
11磅==>16畫素, PPI=104.72727272727
12磅==>17畫素, PPI=102
13磅==>18畫素, PPI=99.692307692308
14磅==>19畫素, PPI=97.714285714286
15磅==>21畫素, PPI=100.8
16磅==>22畫素, PPI=99
17磅==>23畫素, PPI=97.411764705882
18磅==>25畫素, PPI=100
19磅==>26畫素, PPI=98.526315789474
20磅==>27畫素, PPI=97.2
21磅==>28畫素, PPI=96
22磅==>29畫素, PPI=94.909090909091
23磅==>30畫素, PPI=93.913043478261
24磅==>32畫素, PPI=96
25磅==>33畫素, PPI=95.04
26磅==>34畫素, PPI=94.153846153846
27磅==>35畫素, PPI=93.333333333333
28磅==>36畫素, PPI=92.571428571429
29磅==>38畫素, PPI=94.344827586207
30磅==>39畫素, PPI=93.6
31磅==>40畫素, PPI=92.903225806452
32磅==>41畫素, PPI=92.25
33磅==>43畫素, PPI=93.818181818182
34磅==>44畫素, PPI=93.176470588235
35磅==>46畫素, PPI=94.628571428571
36磅==>47畫素, PPI=94
37磅==>48畫素, PPI=93.405405405405
38磅==>48畫素, PPI=90.947368421053
39磅==>50畫素, PPI=92.307692307692
40磅==>51畫素, PPI=91.8
41磅==>52畫素, PPI=91.317073170732
42磅==>53畫素, PPI=90.857142857143
43磅==>55畫素, PPI=92.093023255814
44磅==>56畫素, PPI=91.636363636364
45磅==>57畫素, PPI=91.2
46磅==>58畫素, PPI=90.782608695652
47磅==>60畫素, PPI=91.914893617021
48磅==>62畫素, PPI=93
49磅==>63畫素, PPI=92.571428571429
50磅==>63畫素, PPI=90.72
51磅==>64畫素, PPI=90.352941176471
52磅==>67畫素, PPI=92.769230769231
53磅==>68畫素, PPI=92.377358490566
54磅==>69畫素, PPI=92
55磅==>70畫素, PPI=91.636363636364
56磅==>71畫素, PPI=91.285714285714
57磅==>72畫素, PPI=90.947368421053
58磅==>74畫素, PPI=91.862068965517
59磅==>75畫素, PPI=91.525423728814
60磅==>76畫素, PPI=91.2
61磅==>77畫素, PPI=90.885245901639
62磅==>78畫素, PPI=90.58064516129
63磅==>79畫素, PPI=90.285714285714
64磅==>81畫素, PPI=91.125
65磅==>83畫素, PPI=91.938461538462
66磅==>84畫素, PPI=91.636363636364
67磅==>85畫素, PPI=91.34328358209
68磅==>86畫素, PPI=91.058823529412
69磅==>86畫素, PPI=89.739130434783
70磅==>88畫素, PPI=90.514285714286
71磅==>90畫素, PPI=91.267605633803
72磅==>91畫素, PPI=91
73磅==>92畫素, PPI=90.739726027397
74磅==>93畫素, PPI=90.486486486486

可見當大於46磅時,PPI穩定在90,而小於46磅時,PPI一直在微變。
所以,如果你想繪製20個畫素大小的字型,那麼必須設定$size引數為:14.5磅。
另外需要注意的是,$size並不完全對應字型的顯示大小,因為同樣的$size,不同的字元佔據的空間並不是一樣的。例如,漢字“國”的寬度會比數字1的寬度大得多,對於標點符號,則更是這樣,半形和全形符號也不同。
總之,使用imageTtfText()不可能精確控制到畫素級別,只能大概。這也算是向量字型的一個小缺陷。

(3)$angle是旋轉角度。這個官網解釋的比較清楚,需要說明有兩點:一是角度單位是度而不是弧度,二是旋轉的中心點就是引數$x,$y。

(4)(5)$x,$y 被繪製字串的第一個字元的基線點。單位是畫素。這裡涉及到字型設計的基本知識--基線。這個點絕對不是左上角,而具體是什麼取決於所使用的字型是如何設計的。對於宋體、楷體、黑體等常見的字型中的漢字,這個點大概位於字型的左下部分;而對於英文字母和標點符號,則各不相同。如下圖:


(6)$color 字型的顏色,不多解釋。

(7)$fontfile 字型檔案。也就是包含trueType字型字模的檔案,如楷體字型檔案simkai.ttf。這種檔案的格式是有標準規範的,而且與平臺無關。所以可以直接把Windows系統的字型檔案拷貝到Linux下使用。

(8)$text 要渲染的字串。需要注意必須是UTF-8編碼的字串。說到字串不得不提PHP的string資料型別。雖然名為string,其實PHP語言本身並不認識各種字元編碼,它只是簡單的把string看做是動態增長的“位元組”陣列,例如strlen()就是返回的位元組數。而我們知道除了ASCII編碼的字元和位元組是相同的外,幾乎沒有其他字元編碼中的字元對應一個位元組,例如一個漢字的UTF-8編碼佔用3個位元組。至於怎麼解釋其中的字元編碼,需要專門的庫函式如iconv_strlen()。如果字串使用字面量,那麼其所在的php原始檔就必須編碼為UTF-8儲存。

2 幾個小技巧
(1)字處理軟體的複雜之處
儘管這個函式可以顯示字串,但是針對於字處理軟體(如Word)來說,並不能使用。因為一旦涉及到對其的問題,此函式即不能使用了。因為它不能處理字間距,當然也就無法實現分散對齊等功能。再加上每行的“避首尾”(如,不能位於行首)要求,做好字處理並不簡單。

變通的方式是,首先通過複雜的公式計算出各個字元的準確位置,然後針對每一個字元呼叫此函式。

(2)如何顯示加粗字型
對於本身就有粗體的字型檔案來說,這不存在任何問題,只要使用粗體檔案就可以了。問題是很多字型檔案並沒有針對粗體單獨設計。GD庫中也沒有一個能加粗顯示的函式。其解決方法說出來有點可笑,就是針對每個字元繪製兩次,第二次繪製時的$x會第一次的$x多1個畫素即可。
--------------------- 
作者:smstong 
來源:CSDN 
原文:https://blog.csdn.net/smstong/article/details/43955705 
版權宣告:本文為博主原創文章,轉載請附上博文連結!