2009-12-19 22 views
5

此图像是用PIL创建的。看看这张图片中的g和y是如何切断的?我怎样才能防止这一点?字体与PIL剪辑

http://img109.imageshack.us/img109/8874/screenshotep.png

创建此图像的代码是非常直截了当(略):

import Image, ImageDraw, ImageFont 

im = Image.new("RGBA", (200, 200), 'white') 
draw = ImageDraw.Draw(im) 

font = ImageFont.truetype("VeraSe.ttf", 12) 

draw.text(
      (1, 1), 
      " %s: " % "ggjyfFwe__", 
      font=font, 
      fill='black' 
) 

draw.text(
      (1, 30), 
      " %s" % 15, 
      font=font, 
      fill='black' 
) 

im.show() 

我有一些不同的字体试了一下,它总是被剪掉。令人惊讶; y,谷歌“PIL字体剪辑”返回很少有用的命中...我在Ubuntu 9.10上使用python 2.6.4和PIL 1.1.6

+0

更好地告诉我们你试过的具体字体,以及你在哪个平台上。我刚刚在Win7上用consola.ttf尝试过,并且没有看到你看到的背景覆盖。 –

+0

不幸的是,我没有VeraSe.ttf在这里,你还没有提到你的平台。我怀疑Linux,而不是Windows,并且这是一个特定于平台的问题。 –

+0

对于我来说,使用Python 9.10中Python 2.6的PIL 1.1.7的georgia.ttf(msttcorefonts包的一部分)也会发生这种情况。这似乎是PIL的一个问题,无论它临时呈现的缓冲区不够高。 –

回答

0

我的建议是,在创建图像对象之前,获取文本所需的大小。

这是使用font.getsize("text")documentation)完成的。

在我制作的图片生成脚本中,我首先通过调用font.getsize("Åj")(如果您只需要US-ASCII,您可以找到"Aj"的高度)的等价函数来找到一行文本的最大高度。然后我计算了所需的图像高度和线偏移量,包括边距和线间距。

+0

我已经尝试过类似的东西。如果线条高度不够,PIL将重叠文本而不是剪裁它... – priestc

1

我无法使用迄今为止提到的方法解决某些字体的问题,所以我最终使用aggdraw作为PIL文本drawig方法的透明替代品。

您的代码重写,以aggdraw会是什么样子:

import Image 
import aggdraw 

im = Image.new("RGBA", (200, 200), 'white') 
draw = aggdraw.Draw(im) 

# note that the color is specified in the font constructor in aggdraw 
font = aggdraw.Font((0,0,0), "VeraSe.ttf", size=12, opacity=255) 

draw.text((1, 1), " %s: " % "ggjyfFwe__", font) # no color here 
draw.text((1, 30), " %s" % 15, font) 

draw.flush() # don't forget this to update the underlying PIL image! 

im.show() 
+0

工程!虽然Aggdraw需要在Windows上进行一些修补,但是对于崩溃(http://comments.gmane.org/gmane.comp.python.image/1959)的aggdraw.cxx和使用Freetype2(从gnuwin32获得一个)的setup.py进行构建。 – ogurets

0

“虫” 依然存在,2012年,与Ubuntu 11.10。 Fontsize 11,12,13和15将下划线完全剪切。

#!/usr/bin/env python 
""" demonstrates clipping of descenders for certain font sizes """ 
import Image, ImageDraw, ImageFont 
fontPath = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf" 
im = Image.new('L', (256, 256)) 
ys=15 
for i in range(10,21): 
    fh = ImageFont.truetype(fontPath, i) 
    sometext="%dgt_}" % (i) 
    ImageDraw.Draw(im).text((10, ys),sometext , 254, fh) 
    ys+=i+5 
im.show() 
+1

查看下面的替代使用aggdraw ... –

0

这是一个适合我的kludge。这是关于gnud的答案的一个变种。 (与我希望的评论相比,值得单独回答与评论不同)我已经测试了很多单词展示位置,并且一直执行此操作。

如果绘制的文本未完全达到字体的整个高度,则可能会发生裁剪。正如gnud指出的那样,通过使用诸如“Aj”(我使用“Fj”)这样的字符,您可以避免此错误。

每当一个字放在:

1)做一个draw.textsize(文字,字体=字体)你需要的单词。存储高度/宽度。 2)在单词的末尾添加'Fj'(spaceFJ),并重新设置文本大小并存储第三个高度/宽度。

4)您将使用第2项中的单词(末尾带有'Fj')进行实际文字绘制。有了这个附录将保持字体不被剪辑。

4)在你进行实际的文本绘制之前,裁剪'Fj'所在的图像(需要crop.load()以避免延迟复制)。然后绘制文本,并将裁剪后的图像重新放在'Fj'上。

这个过程避免了剪辑,看起来合理的表现,并产生完整的,未剪辑的文本。以下是我为此使用的一段Python代码的复制/粘贴。部分例子,但希望它增加了一些见解。

# note: xpos & ypos were previous set = coordinates for text draw 
    #  the hard-coded addition of 4 to c_x likely will vary by font 
    #  (I only use one font in this process, so kludged it.) 
    width, height = draw.textsize(word, font=font) 
    word2 = word + ' Fj' 
    width2, height2 = draw.textsize(word2, font=font) 
    # crop to overwrite ' Fj' with previous image bits 
    c_w = width2 - width 
    c_h = height2 
    c_x = xpos + width + 4 
    c_y = ypos 
    box = (c_x, c_y, c_x + c_w, c_y + c_h) 
    region = img.crop(box) 
    region.load() 
    draw.text((xpos, ypos), word2, (0,0,0), font=font) 
    img.paste(region, box)