views:

902

answers:

3

Note: I am cross-posting this from App Engine group because I got no answers there.

As part of my site about Japan, I have a feature where the user can get a large PNG for use as desktop background that shows the user's name in Japanese. After switching my site hosting entirely to App Engine, I removed this particular feature because I could not find any way to render text to a PNG using the image API.

In other words, how would you go about outputting an unicode string on top of an image of known dimensions (1024x768 for example), so that the text will be as large as possible horizontally, and centered vertically? Is there a way to do this is App Engine, or is there some external service besides App Engine that could make this easier for me, that you could recommend (besides running ImageMagick on your own server)?

+2  A: 

[Stop press: As comment suggests - this answer doesn't work in Googe App Engine.]

The Python Imaging Library (PIL) can accomplish this.

You can load in the image, draw Unicode text on it with the ImageDraw.text() function.

You may need to call ImageDraw.textsize() a few times with different font sizes to find thelargest font that will fit.

Finally, you can save the .png image to a file (or serve it back directly).

Test with large images if you are running it from within the context of a web-server, to make sure you can allocate sufficient memory to processs large PNG files.

(Have I answered your question appropriately? I don't know if PIL is an option from within the Google App Engine.)

Oddthinking
Unfortunately, PIL is not available on GAE. There is an Image library, but it has only a subset of PIL functionalities.
Roberto Liffredo
Thanks for the good attempt though :)
Bemmu
+12  A: 

Solution #1. Pure Python image library.

You can try to bundle PyPNG with your application. PyPNG is a pure Python library to create PNG images. It depends on zlib module, which is allowed on AppEngine, so PyPNG should work on AppEngine. Just use StringIO objects instead of files and write PNG data to them.

Shamelessly adapting PyPNG example how to make a bitmap PNG image:

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()

I suspect suboptimal performance, but as far as I know there is no other way to generate images on GAE.

And you still need to figure out how to rasterize text to produce bitmap data. The easiest way, probably, is just to keep bitmaps of all the symbols around (essentially, using a bitmap font).

To render ASCII text with PyPNG take a look at texttopng script.

So, limitations are:

  • Probably slow (needs to be checked)
  • Glyph rasterization is to be addressed

Solution #2. Off-site text-to-image rendering.

Google AppEngine does not provide tools to render text as raster images, but Google Charts does. With a proper choice of parameters, the outline text chart just renders simple text to PNG images.

For example, 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:|Здра́вствуйте|こんにちは|नमस्ते|你好|שלו produces this:

text-to-image on Google Charts

Limitations:

  • You cannot generate images bigger than 300000 pixels
  • Style and font customizations are limited
  • Some Unicode scripts are not available
  • White background only
jetxee
If I had a bitmap of every character though, then I could just use PIL to composite them and wouldn't really need PyPNG anymore. But interesting to know that a library like this exists.
Bemmu
No, you cannot use full PIL on AppEngine, as far as I know, only GAE Images API. Correct me if I am wrong.
jetxee
I voted down because an image library that can't render text is useless.
hasen j
I updated the answer with a Google Charts example.
jetxee
+1 PyPng now has a method to make image from text
Gabriel
Thank you Gabriel. I added a link to texttopng script.
jetxee
+7  A: 

I ran into this same problem with writing text to an image. The issue at hand is that any imaging libraries used on google app engine must be pure python, which rules out PIL.

PyBMP

PyBMP is a pure-python library that can do simple text rendering. From there you can use google's imaging library to composite the resulting bitmap onto your other pictures. There's some sample code below. The downside is the library lacks nicer features like anti-aliasing and fine control over fonts so the text that it renders looks kind of crappy. It also may or may not handle unicode well.

# 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)

After this you can use google's composite function on text_img.getBitmap() as you would any other image.

External Image Processing

If the text isn't good enough (it wasn't for my project), an alternative solution is to set up an external server on a service like Rackspace purely for image processing. Set up an HTTP handler that does your image processing with PIL, and then returns the resulting image. From there you can either

  • upload the result straight to your static file hosting server (like s3) or
  • get the generated-text image result with app engine's urlfetch library and do the rest of your compositing in app engine

Not pretty, but it gets the job done.

Derek Dahmer
PyBMP and PyPNG combined together provide both text rendering and PNG compression. +1.
jetxee