2011-04-21 74 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位掩码。唯一的问题是如何从应用程序中提取或获取它们。我真的不知道,我把这些看作是遗留的东西。我更喜欢现实的渲染问题。

相关问题