在Google App Engine中操作图像

标签:Google App Engine, Python

操作图像大概是Google App Engine中最有趣的功能了。
由于GAE不允许浏览者上传文件到服务器,所以存放到数据库就成了不二选择。可喜的是,如果你只是存储和显示图片,甚至连图像API都不需要用到,直接当成db.Blob类型的数据来使用即可。而且由于Google的慷慨,数据库空间是不限的,你可以在数据库中存放任意大小的文件(不过有流量限制)。

GAE提供了一些图像API来操作图像,包括调整大小、旋转、水平翻转、垂直翻转、截取及自动调整色彩和对比度,支持的图像格式有:JPEG、PNG、GIF(包括动画格式)、BMP、TIFF和ICO 。

事实上,GAE提供的只是Python Imaging Library的部分API,功能很简单,但也很容易学。
如果你要在本地开发服务器上使用,需要先安装PIL,是个几百KB的小东西。如果是在Google的服务器上,则已经默认添加了该库的部分图像转换API。

这些图像API非常简单,在使用图像API的文档里有效果演示,再参考图像类文档函数文档,就能掌握其用法了。
提2个注意点:
1.本地开发服务器里是没有im_feeling_lucky这个函数的(因为PIL里没有这个API)。
2.Image类里有个execute_transforms方法,只有执行这个方法后,对图像的操作才会有效(并且是在这个方法返回,而不是改变原图像)。使用这个方法是会单独算在配额里的。
而images模块则没有这个函数,每次调用它的函数,都会立即生效。
并且,它们的输出格式都只有PNG和JPEG两种,也就意味着不能生成动态的GIF图像。

下面来看个例子:

首先是上传图片,注意指定编码方式(enctype="multipart/form-data")和输入类型(input type="file"):
self.response.out.write("""
          <form action="/sign" enctype="multipart/form-data" method="post">
            <div><label>Message:</label></div>
            <div><textarea name="content" rows="3" cols="60"></textarea></div>
            <div><label>Avatar:</label></div>
            <div><input type="file" name="img"/></div>
            <div><input type="submit" value="Sign Guestbook"></div>
          </form>
        </body>
      </html>""")
接着是存储图片:
from google.appengine.api import images

class Guestbook(webapp.RequestHandler):
  def post(self):
    greeting = Greeting()
    if users.get_current_user():
      greeting.author = users.get_current_user()
    greeting.content = self.request.get("content")
     #转换图像为32×32像素,如果不转换的话,直接greeting.avatar = db.Blob(self.request.get("img"))就行了
    avatar = images.resize(self.request.get("img"), 32, 32)
    greeting.avatar = db.Blob(avatar)
    greeting.put()
    self.redirect('/')
然后生成图像链接:
self.response.out.write("<div><img src='img?img_id=%s'></img>" %
                              greeting.key()) #直接使用key,无需设置index
self.response.out.write(' %s</div>' %
                              cgi.escape(greeting.content))
最后是输出图像:
class Image (webapp.RequestHandler):
  def get(self):
    #根据key从数据库中取出图像
    greeting = db.get(self.request.get("img_id"))
    if greeting.avatar:
      #设置输出格式为PNG
      self.response.headers['Content-Type'] = "image/png"
      self.response.out.write(greeting.avatar)
    else:
      #找不到图像,输出404错误
      self.error(404)
这样,这个从上传到显示的代码就结束了,完整版本可以看Google的文档
当然,你还可以对其进行一些改进,例如存放到memcache中静态化图像链接

此外,Google已经增加了单次上传数据的限制(10MB),但db.Blob类型最大只能存储1MB数据,如果你有需求的话,可以弄10个db.BlobProperty类型的属性,将其分成10个部分存储,输出时再合并。不过从数据库里取那么大的实体,应该是很影响性能的。

最后给个上传图像的演示站点:http://keakon.appspot.com/image

2010年12月1日更新:
如果需要自己生成图像,可以使用PNGCanvas(功能并不完备)。

0条评论 你不来一发么↓

    想说点什么呢?