Python/Django 从URL下载图像,修改并保存到ImageField
我一直在寻找一种方法,可以从一个网址下载图片,对图片进行一些处理(比如调整大小),然后把它保存到Django的ImageField里。通过下面提到的两篇很棒的文章,我已经能够下载并保存图片到ImageField了。不过,在拿到文件后,我在处理它时遇到了一些麻烦。
具体来说,模型的save()方法需要一个File()对象作为第二个参数。所以我的数据最终必须是一个File()对象。下面的博客文章展示了如何使用urllib2把图片网址保存为File()对象。这很好,但我还想用PIL把图片处理成Image()对象(或者ImageFile对象)。
我更希望的做法是直接把图片网址加载到一个Image()对象中,进行调整大小的操作,然后转换成File()对象,最后保存到模型里。不过,我尝试把Image()转换成File()时失败了。如果可能的话,我想尽量减少写入磁盘的次数,所以我希望能在内存中完成这个对象的转换,或者使用一个NamedTemporaryFile(delete=True)对象,这样就不用担心多余的文件留在那儿。(当然,我希望文件在通过模型保存后能写入磁盘)。
import urllib2
from PIL import Image, ImageFile
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile
inStream = urllib2.urlopen('http://www.google.com/intl/en_ALL/images/srpr/logo1w.png')
parser = ImageFile.Parser()
while True:
s = inStream.read(1024)
if not s:
break
parser.feed(s)
inImage = parser.close()
# convert to RGB to avoid error with png and tiffs
if inImage.mode != "RGB":
inImage = inImage.convert("RGB")
# resize could occur here
# START OF CODE THAT DOES NOT SEEM TO WORK
# I need to somehow convert an image .....
img_temp = NamedTemporaryFile(delete=True)
img_temp.write(inImage.tostring())
img_temp.flush()
file_object = File(img_temp)
# .... into a file that the Django object will accept.
# END OF CODE THAT DOES NOT SEEM TO WORK
my_model_instance.image.save(
'some_filename',
file_object, # this must be a File() object
save=True,
)
用这种方法时,文件在我查看时总是显示损坏。有没有人有办法可以从网址获取文件,允许我把它作为Image处理,然后再保存到Django的ImageField里?
任何帮助都非常感谢。
更新 08/11/2010:我最终选择了StringIO,不过,当我尝试把它保存到Django的ImageField时,StringIO抛出了一个异常。具体来说,堆栈跟踪显示了一个名称错误:
"AttribueError exception "StringIO instance has no attribute 'name'"
经过查阅Django的源代码,发现这个错误是因为模型的save方法试图访问StringIO“文件”的大小属性时引起的。(虽然上面的错误提示表明是名称的问题,但这个错误的根本原因似乎是StringIO图像缺少大小属性)。一旦我给图像文件的大小属性赋值,它就正常工作了。
1 个回答
为了实现一举两得,为什么不使用(c)StringIO对象来代替NamedTemporaryFile呢?这样你就不需要把文件存储在硬盘上了。我知道像这样的做法是可行的(我自己也用过类似的代码)。
from cStringIO import StringIO
img_temp = StringIO()
inImage.save(img_temp, 'PNG')
img_temp.seek(0)
file_object = File(img_temp, filename)