2010-08-10 58 views
10

我一直在寻找一种方式来从URL下载图像,对其执行一些图像操作(调整大小)操作,然后将其保存到django ImageField。使用这两个伟大的文章(下面链接),我已经能够下载并保存图像到一个ImageField。但是,一旦拥有它,我一直在操作文件时遇到一些麻烦。Python/Django下载从URL的图像,修改,并保存到ImageField

具体来说,模型字段save()方法需要File()对象作为第二个参数。所以我的数据最终必须是一个File()对象。下面链接的博客文章展示了如何使用urllib2将您的图片URL保存到File()对象中。然而,这非常棒,我也想使用PIL作为Image()对象来操作图像。 (或ImageFile对象)。

我的首选方法是直接将图像URL加载到Image()对象中,执行调整大小,然后将其转换为File()对象,然后将其保存在模型中。但是,我尝试将Image()转换为File()失败。如果可能的话,我想限制写入磁盘的次数,所以我想在Memory中做这个对象转换或者使用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, 
     ) 

使用这种方法时,只要我将该文件作为图像进行查看,就会出现损坏。有没有人有任何方法从URL获取文件文件,允许将其作为图像进行处理,然后将其保存到Django ImageField中?

任何帮助,非常感谢。

Programmatically saving image to Django ImageField

Django: add image in an ImageField from image url

更新08/11/2010:我没有最终用StringIO去,不过,我是StringIO的被扔一个不寻常的例外,当我试图将其保存在一个Django的ImageField。具体来说,堆栈跟踪显示的名称错误:

"AttribueError exception "StringIO instance has no attribute 'name'" 

通过Django的源挖掘后,它看起来像这样的错误是当模型保存尝试访问StringIO的“文件”的大小属性造成的。 (尽管上面的错误表明名称存在问题,但此错误的根本原因似乎是StringIO映像中缺少大小属性)。只要我给图像文件的size属性赋值,它就可以正常工作。

+0

我也用StringIO将图像保存到内存,然后用File.open()读取它,但也有一些问题。 – 2010-08-10 02:26:28

回答

4

试图用1块石头杀死2只鸟。为什么不使用(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) 
+0

谢谢WoLpH,感谢您的帮助。我试过你的解决方案,但仍然遇到一些麻烦。具体来说,当我最后调用save()时,我得到AttribueError异常“StringIO实例没有属性'name'” ------------------ img_temp = StringIO .StringIO(); inImage.save(img_temp,format ='PNG'); img_temp.seek(0); – 2010-08-10 06:17:55

+1

@Joe J:当使用'StringIO'时,'filename'参数是强制性的。那是你现在的问题;) – Wolph 2010-08-10 10:14:53

+0

再次感谢WoLpH。文件名是否必须与文件系统上的路径相对应,还是只能是临时文件的一些随机名称? – 2010-08-10 18:23:10