在App Engine(Python)上将文本转换为PNG

24

注意:我从App Engine组中发布此帖子,因为那里没有得到答案。

作为我关于日本的网站的一部分,我有一个功能,用户可以获得一个显示其姓名日语字符的大PNG图片用作桌面背景。在完全将我的网站托管到App Engine后,我删除了这个特定的功能,因为我找不到使用图像API将文本呈现为PNG的方法。

换句话说,您如何在已知尺寸的图像(例如1024x768)上输出Unicode字符串,以使文本水平尽可能大,并在垂直方向上居中对齐?是否有一种在App Engine中实现此目的的方法,或者除了在自己的服务器上运行ImageMagick之外,您还能推荐其他外部服务来简化此过程?


请注意,我将考虑一些可靠且价格合理的外部服务作为有效答案。任何可以使我免于维护机器以便生成一些文本PNG的服务都可以。这样的服务应该至少每秒处理10个1024 x 768的图像创建。 - Bemmu
如果您能描述GAE可以做什么和不能做什么,那就太好了。并不是每个人都知道GAE能做什么,但如果您告诉了限制,也许有人会有解决方案。例如,您能运行Linux命令吗?比如说.. pango-view - hasen
4个回答

30

解决方案 #1. 使用纯Python图像库。

您可以尝试将 PyPNG 与您的应用程序捆绑在一起。 PyPNG是一个用于创建PNG图像的纯Python库。它依赖于zlib模块,在AppEngine上是允许的,因此PyPNG应该可以在AppEngine上工作。只需使用StringIO对象代替文件并将PNG数据写入它们。

无耻地改编了PyPNG如何制作位图PNG图像的示例:

import png
from StringIO import StringIO

# bitmap data
s = ['110010010011',
     '101011010100',
     '110010110101',
     '100010010011']
s = map(lambda x: map(int, x), s)

f = StringIO()
w = png.Writer(len(s[0]), len(s), greyscale=True, bitdepth=1)
w.write(f, s)

# binary PNG data
print f.getvalue()

我怀疑表现亚优,但据我所知,在GAE上没有其他生成图像的方法。

而且你仍然需要想办法栅格化文本以产生位图数据。最简单的方法可能就是保留所有符号的位图(基本上是使用位图字体)。

要使用PyPNG呈现ASCII文本,请查看texttopng脚本。

因此,限制如下:

  • 可能很慢(需要检查)
  • 需要解决字形光栅化问题

解决方案#2。离线文本到图像渲染。

Google AppEngine不提供将文本呈现为光栅图像的工具,但Google Charts提供此功能。通过正确选择参数,轮廓文本图表只需将简单文本呈现为PNG图像。

例如,http://chart.apis.google.com/chart?chst=d_text_outline&chld=000000|32|h|FFFFFF|_|Render text to image|with Google Charts.|Some Unicode too:|Здра́вствуйте|こんにちは|नमस्ते|你好|שלו会生成以下图像:

text-to-image on Google Charts

限制如下:

  • 您无法生成大于300000个像素的图像
  • 样式和字体定制有限
  • 某些Unicode脚本不可用
  • 仅支持白色背景

如果我有每个字符的位图,那么我可以使用PIL将它们合成,就不再需要PyPNG了。但是知道存在这样的库还是很有趣的。 - Bemmu
2
不,据我所知,你不能在AppEngine上使用完整的PIL,只能使用GAE Images API。如果我错了,请纠正我。 - sastanin
2
我投反对票,因为一个不能渲染文本的图像库是无用的。 - hasen
谢谢Gabriel。我已经添加了一个到texttopng脚本的链接。 - sastanin

9

我在将文本写入图像时遇到了相同的问题。问题在于在Google应用引擎上使用的任何图像库都必须是纯Python的,这就排除了PIL。

PyBMP

PyBMP是一个纯Python库,可以进行简单的文本渲染。从那里,您可以使用Google的图像库将生成的位图合成到其他图片上。下面有一些示例代码。缺点是该库缺乏更好的功能,如抗锯齿和对字体的精细控制,因此它呈现的文本看起来有点糟糕。它也可能无法很好地处理Unicode。

# Create the image
text_img = bmp.BitMap(300,35,bmp.Color.WHITE)
# bmpfont_Tw_Cen_MT_30 is a generated file using PyBMP's tool
text_img.setFont(bmpfont_Tw_Cen_MT_30.font_data)
text_img.setPenColor( bmp.Color.BLACK )
text_img.drawText(name, 0, 0)

在此之后,您可以像使用其他图像一样使用Google的composite函数在text_img.getBitmap()上进行操作。

外部图像处理

如果文本不够好(对于我的项目来说并非如此),另一个解决方案是在像Rackspace这样的服务上设置一个专门用于图像处理的外部服务器。设置一个HTTP处理程序,使用PIL进行图像处理,然后返回结果图像。从那里,您可以选择:

  • 将结果直接上传到静态文件托管服务器(例如s3)或
  • 使用应用程序引擎的urlfetch库获取生成的文本图像结果,并在应用程序引擎中完成其余的合成工作

虽然不太美观,但它能胜任工作。


1
PyBMP和PyPNG结合在一起,可以提供文本渲染和PNG压缩功能。+1。 - sastanin

4

有点晚了,但我在寻找同样的东西。我成功地将Unicode字符串(这里是天城文)绘制到图像上,并通过以下方式将其保存为“.png”文件:

# -*- coding: utf-8 -*-
import Image, ImageDraw, ImageFont

img = Image.new('L', (16,16), 255)
draw = ImageDraw.Draw(img)
text_to_draw = unicode('क','utf-8')
font = ImageFont.truetype('Path/to/font/file',12)
draw.text((2,2), text_to_draw, font = font)
del draw

img.save('image.png')

附注:从stackoverflow上的其他帖子得到了帮助。


3

[重要提示:如评论所示-此答案在Google应用程序引擎中无效。]

Python Imaging Library (PIL) 可以完成此操作。

您可以加载图像,使用ImageDraw.text()函数在其上绘制Unicode文本。

您可能需要调用几次ImageDraw.textsize()并使用不同的字体大小来查找最大的适合字体。

最后,您可以将.png图像保存到文件中(或直接返回它)。

如果在web服务器的上下文中运行,请使用大型图像进行测试,以确保您可以分配足够的内存来处理大型PNG文件。

(我是否已适当回答了您的问题?我不知道从Google App Engine中是否可以使用PIL。)


1
很遗憾,PIL在GAE上不可用。虽然有一个图像库,但它只有PIL功能的子集。 - rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接