2011-04-21 71 views
4

要機智:記事本被打開時,選擇作爲「Arial字體,大小11」的字體,詞「這僅僅是一個測試」小心進入,截取的屏幕截圖:爲什麼我的truetype字體的大小11呈現與Windows不同?

original http://i53.tinypic.com/200skuv.png

以下Python代碼是進入並運行:

import ImageFont, ImageDraw, Image 
im = Image.open("c:/textimg.png") #the above image 

pilfont = ImageFont.truetype("arial.ttf", 11) 

compimg = Image.new("RGB", im.size, (255, 255, 255)) 
draw = ImageDraw.Draw(compimg) 

draw.text((0,0), "this is just a test", (0,0,0), font=pilfont) 

compimg.save("c:/compimg.png") 

然而結果令人失望的不同:

sad http://i56.tinypic.com/9h7x55.png

不僅它是錯誤的大小,但它也有點陰影,而記事本渲染是清晰的,沒有跨越像素邊界。

我怎樣才能讓它像記事本一樣渲染呢?我對pygame也有這個確切的問題,所以我想我在這裏錯過了對TTF的一些基本理解。

更新:我再次用pygame試了一下。它做同樣的事情。它可以選擇關閉消除鋸齒功能,但它看起來只是根據某個閾值來消除任何可能會反鋸齒的像素。我是用大小15.最接近的代碼是:

pygfont = pygame.font.Font(r"c:\windows\fonts\arial.ttf", 15) 
surf = pygfont.render("this is just a test", False, (0,0,0), (255,255,255)) 
pygame.image.save(surf, r"c:\pygameimg.png") 

和結果(在上面記事本原件比較):

KILL ME http://i56.tinypic.com/2r26mbs.png

爾加爲什麼我不能提供一個賞金馬上?

更新:這是比較所有方法:

AIFEOIFEF http://i56.tinypic.com/51ybtg.png

PIL 15,然後記事本11,然後Pygame的15抗鋸齒關閉,然後Pygame的15抗混疊上。

PIL 15實際上具有正確的比例,它只是反鋸齒。所以:爲什麼15比11?如何使它像Windows一樣進行操作? (和跆拳道pygame在做什麼?)

+0

此處的圖片已刪除,您可以更新鏈接嗎? – shuttle87 2015-01-23 03:29:14

回答

4

字體渲染是一個複雜而微妙的過程,並且已經實施了多次。在你的情況下,PIL和Windows看起來不同,因爲它們使用完全不同的字體渲染引擎。 Windows使用其內置的渲染,而PIL使用它編譯的Freetype。

我不知道每個環境如何解釋它的「大小」參數,但即使讓它們解釋相同,渲染也會不同。獲得與記事本相同像素的方法是啓動記事本並抓取屏幕。

也許如果您更多地解釋爲什麼您需要與記事本相同的渲染,我們將爲您的問題提供創意解決方案。

+0

有什麼方法可以使用Python的Python方法渲染?我想呈現與記事本相同的原因是因爲我想自動檢測程序正在使用的字體。如果他們使用一個簡單的不反鋸齒渲染,我只能希望它,並且ive通過使用paint/notepad手動成功匹配它們並將其與屏幕截圖進行比較,所以這就是我試圖模仿的東西。 – Claudiu 2011-04-21 23:09:47

+0

實際上很多程序使用閃光燈,所以如果我能找到一種方法讓閃光燈渲染我的字體,這將是甜.. – Claudiu 2011-04-21 23:13:37

+0

也感謝指出PIL的算法。我正在學習更多的關於字體渲染比我想知道.. – Claudiu 2011-04-21 23:44:05

1

我認爲記事本的「大小」是pointsize和ImageFont.truetype()的「大小」是像素。

+0

和..我能做些什麼嗎?我想呈現與記事本一樣的效果,特別是要擺脫可能發生的任何反鋸齒 – Claudiu 2011-04-21 19:49:15

+0

我也不確定這是否屬實。記事本中'h'的高度是11,而'h'的高度是PIL的7或8。 – Claudiu 2011-04-21 20:01:37

1

尺寸出來不同,因爲它們的指定不同。要將點轉換爲像素,請使用公式:pixels = points * 96/72其中,96是配置到Windows中的DPI(不是顯示器的實際DPI)。在你的情況下,11 * 96/72 = 14.6666,這輪到15。

至於使文本像素對像素完全相同,這將不可能提供的工具 - Ned is correct。如果這非常重要,則需要使用Windows API爲您呈現此文本並將其複製到圖像中。不是一個簡單的過程。

+0

嗯,你可以給我一個指針,我可以開始使用winapi來渲染文本? – Claudiu 2011-04-21 23:10:14

1

成功 - 看看紅線:

praise the lord http://i54.tinypic.com/2r60dc3.png

使用我創建here方法。

有趣的是,我仍然有供應的字體大小15.我不知道這是否與點的關係,雖然像素,作爲文檔說:

> 0:字體映射器轉換此值轉換爲設備單位,並將其與可用字體的單元高度進行匹配。

< 0:字體映射器將該值轉換爲設備單位,並將其絕對值與可用字體的字符高度相匹配。

然而,提供-11沒有得到預期的結果......它只是使它變小..所以我不知道。這可能是點對像素。

1

正如Ned已經指出的,嘗試從某個渲染庫中獲得相同的結果並不是很正確。如果你想完全相同的本機外觀,你試圖去到Windows的內部功能,這是你已經完成,因爲我從你的其他帖子看到,這是非常有趣的。

如果我們一般說到屏幕的真實文本渲染,有一些重要的細微差別。首先,所有的矢量字體格式最初並不是針對屏幕開發的,而僅僅針對印刷術,以及它的兩大差異。 對於屏幕,您只需要一個位圖,即8位alpha通道信息,然後將其與像素值一起融合到屏幕背景。 爲了讓事情順利進行,您需要逐字地將TTF文件轉換爲一組位圖。

這裏有兩條路走,粗略地講:在BW(1位)高分辨率

  • 提取物字形。例如。在大多數情況下,〜600px的位圖就足夠了。然後,您可以根據需要構建和調整字符串大小。

  • 將它們直接解壓到目標分辨率爲8位數組。在這種情況下,你不能調整它們的大小,但只能構造字符串,只需將這個8位數組放在alpha通道中並沿着這條線放置即可。

在這兩種情況下,你還需要精確的距離列表和字距對名單,這是每一個目標的分辨率和提取這些信息可以爲不同的字體格式差異明顯不同。

堅持第一步比較好,因爲第二種方法也可以從高分辨率位圖中實現,無需每次光柵化。 對於小尺寸以獲得更好的距離精度,您還可以生成「移位」字形,這意味着相同的字形,但在初始高分辨率圖像中移動1/2或1/3像素。這又需要稍微不同的字符串構造過程。

重要關於尺寸的注意事項:沒有字體大小這樣精確的東西。在印刷術中,這是Em square的大小,並且不與字體的x高度直接相關。此外,如果我進行位圖渲染或重新採樣,我只能使用Em平方的像素大小(整個位圖的邊界)和下采樣因子,如果我使用它來獲取小的位圖。真正的x高度大小可以近似計算,僅供參考。

對於您的非抗鋸齒位圖,這些小的位圖必須已經包含在字體文件中,至少對於像Arial和Times這樣的原生字體。 IIRC這些存儲在TTF內的特殊小尺寸7-16磅通常和1位掩碼。唯一的問題是如何從應用程序中提取或獲取它們。我真的不知道,我把這些看作是遺留的東西。我更喜歡現實的渲染問題。

相關問題