php在图片上绘制汉字之imageTtfText()函数
圖片處理,是許多程序的功能之一;而文字渲染則是繪圖的基本組成部分。PHP通過(guò)很多擴(kuò)展庫(kù)來(lái)支持圖片的處理,最常用的還是GD庫(kù),通過(guò)一系列imagexxx()函數(shù)來(lái)提供繪圖功能。本文專(zhuān)注于非常細(xì)小的一點(diǎn):繪制文字。熟悉Win32的人都知道,TextOut()就可以輕松顯示任何文字了,然而到了PHP的世界里,有些事情并不輕松。
1 詳細(xì)解釋imageTtfText()函數(shù)
對(duì)于PHP繪圖初學(xué)者,首先遇到的一個(gè)問(wèn)題就是,imageString()這個(gè)函數(shù)并不支持漢字的繪制。這往往會(huì)給入門(mén)者當(dāng)頭一棒,不過(guò)不要著急,因?yàn)檫€有一個(gè)imageTtfText()函數(shù),這個(gè)函數(shù)能繪制UTF-8編碼的字符串,當(dāng)然可以繪制漢字了。然而使用它并不十分簡(jiǎn)單。先來(lái)看看其原型聲明:
?
一共有8個(gè)參數(shù),缺一不可,而且官方文檔這些參數(shù)的解釋并不透徹,這里筆者盡力做更詳細(xì)清晰的解釋:
(1)$image 這個(gè)是畫(huà)布資源,無(wú)需再解釋;
(2)$size,官方文檔的解釋是,字體大小,其長(zhǎng)度單位依賴(lài)于GD庫(kù)的版本,對(duì)于GD1來(lái)說(shuō)是像素,對(duì)于GD2來(lái)說(shuō)是磅(point)。現(xiàn)在一般都是GD2了,那么這個(gè)磅究竟是什么意思呢?這涉及到字體設(shè)計(jì)的基本知識(shí)。
簡(jiǎn)單來(lái)說(shuō),磅是一個(gè)長(zhǎng)度度量單位,如果把一英寸等分成72份,每一份就是1磅。這里需要強(qiáng)調(diào)的是,磅是個(gè)絕對(duì)物理單位,與顯示設(shè)備無(wú)關(guān)。
而像素呢?像素沒(méi)有固定的大小,而是與分辨率相關(guān),高分辨率的顯示器像素就很小,如iphone視網(wǎng)膜屏上一個(gè)像素的大小要比普通LCD顯示器的像素小很多。然而有些東西是不存在分辨率這個(gè)概念的,如單純的位圖圖片,它的最小組成部分就是像素,本身也是通過(guò)每個(gè)像素的顏色值來(lái)定義的。把同樣的圖片顯示在不同分辨率的顯示器上,最終呈現(xiàn)出的大小是不同的。
操作位圖時(shí),以像素位單位最精確合理,那么使用GD2庫(kù)的時(shí)候,如何繪制大小為20像素的字呢?也就是多少磅才能等于20個(gè)像素呢?這必須通過(guò)分辨率才能計(jì)算出來(lái),而問(wèn)題是位圖本身并沒(méi)有分辨率的概念。
現(xiàn)在把問(wèn)題返回來(lái),如果給定$size=20磅,那么imageTtfText()繪制完成時(shí),究竟會(huì)占用多少像素。無(wú)論如何,imageTtfText()最終還是要把文字繪制落實(shí)到具體的位圖像素上。
1磅 = PPI/72 個(gè)像素
這個(gè)問(wèn)題確實(shí)非常棘手,此函數(shù)內(nèi)部必然會(huì)使用某個(gè)分辨率PPI來(lái)計(jì)算被渲染的像素區(qū)域。而GD2庫(kù)卻沒(méi)有提供任何讓用戶設(shè)置或者讀取這個(gè)分辨率的方法。那么,我們只能動(dòng)手測(cè)試了。使用不同的磅值繪制文字,然后測(cè)量文字占據(jù)的像素,通過(guò)公式:
PPI = (72*像素?cái)?shù))/磅值。實(shí)驗(yàn)得出的結(jié)論是:
?
可見(jiàn)當(dāng)大于46磅時(shí),PPI穩(wěn)定在90,而小于46磅時(shí),PPI一直在微變。
所以,如果你想繪制20個(gè)像素大小的字體,那么必須設(shè)置$size參數(shù)為:14.5磅。
另外需要注意的是,$size并不完全對(duì)應(yīng)字體的顯示大小,因?yàn)橥瑯拥?size,不同的字符占據(jù)的空間并不是一樣的。例如,漢字“國(guó)”的寬度會(huì)比數(shù)字1的寬度大得多,對(duì)于標(biāo)點(diǎn)符號(hào),則更是這樣,半角和全角符號(hào)也不同。
總之,使用imageTtfText()不可能精確控制到像素級(jí)別,只能大概。這也算是矢量字體的一個(gè)小缺陷。
(3)$angle是旋轉(zhuǎn)角度。這個(gè)官網(wǎng)解釋的比較清楚,需要說(shuō)明有兩點(diǎn):一是角度單位是度而不是弧度,二是旋轉(zhuǎn)的中心點(diǎn)就是參數(shù)$x,$y。
(4)(5)$x,$y 被繪制字符串的第一個(gè)字符的基線點(diǎn)。單位是像素。這里涉及到字體設(shè)計(jì)的基本知識(shí)--基線。這個(gè)點(diǎn)絕對(duì)不是左上角,而具體是什么取決于所使用的字體是如何設(shè)計(jì)的。對(duì)于宋體、楷體、黑體等常見(jiàn)的字體中的漢字,這個(gè)點(diǎn)大概位于字體的左下部分;而對(duì)于英文字母和標(biāo)點(diǎn)符號(hào),則各不相同。如下圖:
?
(6)$color 字體的顏色,不多解釋。
(7)$fontfile 字體文件。也就是包含trueType字體字模的文件,如楷體字體文件simkai.ttf。這種文件的格式是有標(biāo)準(zhǔn)規(guī)范的,而且與平臺(tái)無(wú)關(guān)。所以可以直接把Windows系統(tǒng)的字體文件拷貝到Linux下使用。
(8)$text 要渲染的字符串。需要注意必須是UTF-8編碼的字符串。說(shuō)到字符串不得不提PHP的string數(shù)據(jù)類(lèi)型。雖然名為string,其實(shí)PHP語(yǔ)言本身并不認(rèn)識(shí)各種字符編碼,它只是簡(jiǎn)單的把string看做是動(dòng)態(tài)增長(zhǎng)的“字節(jié)”數(shù)組,例如strlen()就是返回的字節(jié)數(shù)。而我們知道除了ASCII編碼的字符和字節(jié)是相同的外,幾乎沒(méi)有其他字符編碼中的字符對(duì)應(yīng)一個(gè)字節(jié),例如一個(gè)漢字的UTF-8編碼占用3個(gè)字節(jié)。至于怎么解釋其中的字符編碼,需要專(zhuān)門(mén)的庫(kù)函數(shù)如iconv_strlen()。如果字符串使用字面量,那么其所在的php源文件就必須編碼為UTF-8存儲(chǔ)。
2 幾個(gè)小技巧
(1)字處理軟件的復(fù)雜之處
盡管這個(gè)函數(shù)可以顯示字符串,但是針對(duì)于字處理軟件(如Word)來(lái)說(shuō),并不能使用。因?yàn)橐坏┥婕暗綄?duì)其的問(wèn)題,此函數(shù)即不能使用了。因?yàn)樗荒芴幚碜珠g距,當(dāng)然也就無(wú)法實(shí)現(xiàn)分散對(duì)齊等功能。再加上每行的“避首尾”(如,不能位于行首)要求,做好字處理并不簡(jiǎn)單。
變通的方式是,首先通過(guò)復(fù)雜的公式計(jì)算出各個(gè)字符的準(zhǔn)確位置,然后針對(duì)每一個(gè)字符調(diào)用此函數(shù)。
(2)如何顯示加粗字體
對(duì)于本身就有粗體的字體文件來(lái)說(shuō),這不存在任何問(wèn)題,只要使用粗體文件就可以了。問(wèn)題是很多字體文件并沒(méi)有針對(duì)粗體單獨(dú)設(shè)計(jì)。GD庫(kù)中也沒(méi)有一個(gè)能加粗顯示的函數(shù)。其解決方法說(shuō)出來(lái)有點(diǎn)可笑,就是針對(duì)每個(gè)字符繪制兩次,第二次繪制時(shí)的$x會(huì)第一次的$x多1個(gè)像素即可。
?
轉(zhuǎn)自:https://blog.csdn.net/smstong/article/details/43955705
總結(jié)
以上是生活随笔為你收集整理的php在图片上绘制汉字之imageTtfText()函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 鲜银耳如何处理?
- 下一篇: PHP生成唯一订单号