3

I'm trying to overlay some text over an image on GAE. Now they expose the PIL library it should not be problem.

Here's what I have. It works, but I can't help think I should be writing directly to the background image rather than creating a separate overlay image and then merging.

Can I use Image.frombuffer or something, I've given it a go but I'm just not getting it...

from PIL import Image, ImageDraw, ImageFont
from google.appengine.api import images
from google.appengine.ext import blobstore
from google.appengine.api import files

def compose(key):

    # create new image
    text_img = Image.new('RGBA', (800,600), (0, 0, 0, 0))
    draw = ImageDraw.Draw(text_img)
    draw.text((0, 0), 'HELLO TEXT', font=ImageFont.load_default())

    # no write access on GAE
    output = StringIO.StringIO()
    text_img.save(output, format="png")
    text_layer = output.getvalue()
    output.close()

    # read background image
    blob_reader = blobstore.BlobReader(key)
    background = images.Image(blob_reader.read())

    # merge
    merged = images.composite([(background, 0, 0, 1.0, images.TOP_LEFT), 
                               (text_layer, 0, 0, 1.0, images.TOP_LEFT)], 
                               800, 600)

    # save
    file_name = files.blobstore.create(mime_type='image/png')
    with files.open(file_name, 'a') as f:
        f.write(merged)
    files.finalize(file_name)
bradley
  • 766
  • 2
  • 11
  • 29

3 Answers3

2

You should use the [Image.open][1] method instead. Image.frombuffer and Image.fromstring decode pixel data not raw images.

In your case you could use something like:

blob_reader = blobstore.BlobReader(key)
text_img = Image.open(blob_reader)
.........
bradley
  • 766
  • 2
  • 11
  • 29
Sebastian Kreft
  • 7,191
  • 2
  • 18
  • 36
  • I get an error with that: `raise IOError("cannot identify image file")` – bradley Oct 02 '12 at 18:42
  • What type of image are you trying to load? Also could you try using the following `text_img = Images.open(StringIO(blob_reader.read))`. – Sebastian Kreft Oct 02 '12 at 19:06
  • They are just standard jpegs. I get `TypeError: 'module' object is not callable` with using StringIO. – bradley Oct 02 '12 at 19:33
  • You need to use `from StringIO import StringIO`. – Sebastian Kreft Oct 02 '12 at 19:52
  • That's strange. I tried it in my local environment with a jpeg and it works just fine. Can you download the image and see if you can load it using just plain python + PIL. It may be that PIL does not like the image. – Sebastian Kreft Oct 02 '12 at 20:43
  • Ok, it worked when using the open command in plain python. [Example](http://hastebin.com/geyosapeke.py). So it looks like it's some problem with the blob_reader...? – bradley Oct 02 '12 at 22:38
  • Can you modify your example to read `img = Image.open(StringIO(open('test.jpg').read())))`. Also, did you check that your local image is the same as the one uploaded. – Sebastian Kreft Oct 02 '12 at 22:45
  • That works. Swapping that to `img = Image.open(StringIO(blob_reader.read()))` in my GAE app definitely does not work though... Here is the image: [Image](http://s3.uploader.nodejitsu.com.s3.amazonaws.com/1349218516317/test.jpg) – bradley Oct 02 '12 at 22:59
2

You need to open the image with PIL, not the app engine image type (another answer was off by one character: Image, not Images):

blob_reader = blobstore.BlobReader(key)
text_img = Image.open(blob_reader)
mjibson
  • 16,612
  • 7
  • 27
  • 40
0

To draw directly on the background image would be the most straightforward:

draw = ImageDraw.Draw(background)
draw.text((0, 0), 'HELLO TEXT', font=ImageFont.load_default())
Mark Ransom
  • 271,357
  • 39
  • 345
  • 578