1

我正在使用 Python 2.7.3 和 PIL 1.1.7 在 Windows 7 平台上进行开发。

我正在尝试编写一个 python 脚本来生成一组带有文本的图像。由于我需要包装文本并将其放入任意边界框中,因此我编写了一个方法,该方法将文本绘制到白色 RGBA 背景图像上,并打开 alpha 透明层。为了简化问题,我写了一个小python脚本来说明问题:

import Image,ImageDraw,ImageFont
import webbrowser

# sample text and font
text = "The text quality will degrade with the paste operation."
verdana_font = ImageFont.truetype("verdana.ttf", 20)

# get the line size
text_width, text_height = verdana_font.getsize(text)

# create a blank canvas with extra space between lines
blank_canvas = Image.new('RGB', (text_width + 10, text_height * 10 + 5 * 10), (255, 255, 255))

# create a blank RGBA canvas for the drawn text
text_canvas = Image.new('RGBA', (text_width, text_height), (255, 255, 255, 0))

draw = ImageDraw.Draw(text_canvas)

# draw the text onto the text canvas  
draw.text((0,0), text, font = verdana_font, fill = "#000000")

# print 10 lines
for x in range(0,10):

    # calculate the coordinates for the paste operation and debug 
    coordinates = (5, 5 + (x * (5 + text_height)))
    print "x = %d | coordinates = %r" % (x, coordinates)

    # paste the text onto the blank canvas
    blank_canvas.paste(text_canvas, coordinates, text_canvas)

    # create a temporary canvas
    temp_canvas = Image.new('RGBA', (text_width, text_height), (0, 0, 0, 0)) 

    # paste the text canvas onto the temp canvas using the png alpha layer for transparency
    temp_canvas.paste(text_canvas, (0,0), text_canvas)

    # swap the canvases
    text_canvas = temp_canvas

# save the blank canvas to a file
blank_canvas.save("paste-degradation.png", "PNG")

# open the image up to see the paste operation's image degradation
webbrowser.open("paste-degradation.png")

每次将文本粘贴到新的“临时”画布上时,所绘制文本的图像质量都会越来越差。上面的代码生成的图像如下所示:

文字质量下降

我的代码有问题吗?还是PIL中有错误?

4

1 回答 1

2

问题是 draw.text() 有一个稍微意外的行为。

draw.text() 通过将一些像素设置为fill(肯定在文本内部的像素)来绘制文本,而不是接触其他像素(肯定在文本外部的像素)。但是,如果发现一个像素占文本的 25%,则 draw.text() 将简单地将新像素设置为fill旧值的 25% 和 75%。但是这样的比率独立地应用于 RGBA 的所有 4 个分量。在这个例子中,你的背景是 (255, 255, 255, 0) 并且fill是 (0, 0, 0, 255):所以 25%-in-the-text 像素将是 (192, 192, 192, 64) .

但我认为这不是直观的结果。直观的结果应该是 (0, 0, 0, 64)。如果您将这样的文本粘贴到例如全红色的图像上,那么上面的像素最终仍将贡献 25% 的浅灰色(192、192、192)。换句话说,您将看到灰色边框,您只希望看到黑色、红色和介于两者之间的颜色。

(其实上面的解释太简单了:把背景设置为(0, 0, 0, 0)没有帮助。我怀疑是因为那个颜色实际上是等价于(255, 255, 255, 0),即完全透明。此外,似乎在canvas.paste(img, (0,0), img)调用中使用了相同的算法。)

解决它的一种方法是仅使用从文本中提取的图像的 alpha 波段,即替换temp_canvas.paste(text_canvas, (0,0), text_canvas)temp_canvas.paste("#000000", (0,0), text_canvas).

于 2013-01-21T18:12:46.130 回答