Django PIL: IOError无法识别图像文件

7

我正在学习Python和Django。

用户使用forms.ImageField()提供了一张图片。然后,我需要对其进行处理,以创建两个不同大小的图像。

当我提交表单时,Django会返回以下错误:

IOError at /add_event/
cannot identify image file

我调用了resize函数:

def create_event(owner_id, name, image):         
    image_thumb = image_resizer(image, name, '_t', 'events', 180, 120)  
    image_medium = image_resizer(image, name, '_m', 'events', 300, 200)

当第二次调用image_resizer时,我会收到一个错误:

def image_resizer(image, name, size, app_name, length, height): 
    im = Image.open(image)
    if im.mode != "RGB":
        im = im.convert("RGB")
    im = create_thumb(im, length, height)
    posit = str(MEDIA_ROOT)+'/'+app_name+'/'
    image_2 = im
    image_name = name + size +'.jpg' 
    imageurl = posit + image_name
    image_2.save(imageurl,'JPEG',quality=80)
    url_image='/'+app_name+'/'+image_name  
    return url_image

版本:
Django 1.3.1
Python 2.7.1
PIL 1.1.7

我正在尝试找到问题,但不知道该怎么做。谢谢您的帮助!

编辑
我重写了这个函数,现在它可以批量创建不同的图像:

我调用了resize函数:

url_array = image_resizer.resize_batch(image, image_name, [[180,120,'_t'], [300,200,'_m']], '/events/')  

so:

image_thumb = url_array[0]
image_medium = url_array[1]

并且还有调整大小的功能:
def resize_batch(image, name, size_array, position):
    im = Image.open(image)
    if im.mode != "RGB":
        im = im.convert("RGB")
    url_array = []
    for size in size_array:
        new_im = create_thumb(im, size[0], size[1])
        posit = str(MEDIA_ROOT) + position
        image_name = name + size[2] +'.jpg' 
        imageurl = posit + image_name
        new_im.save(imageurl,'JPEG',quality=90)
        new_url_array = position + image_name
        url_array.append(new_url_array)
    return url_array

感谢所有人!

它是在Image.open()上引发的吗?那里提供了什么路径?那个路径上真的有一个有效的图像文件吗? - ilvar
是的,它是在Image.open()上引发的,它的类型是<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>。现在我正在尝试使用@gareth-rees提出的解决方案来解决问题。 - enri
如果您将文件对象传递给Image.open(),那么该文件对象需要先以二进制模式打开。这可能是问题所在,但无法从您的代码中确定。 - user240515
2个回答

19

正如ilvar在评论中提到的那样image是什么类型的对象?为了回答这个问题,我假设它是由远程用户上传的文件生成的Django ImageFieldfile属性。

在文件上传后,你通过ImageField.file属性获取到的对象是一个TemporaryUploadedFile对象,它可能代表着磁盘上或内存中的文件,这取决于上传文件的大小。这个对象的行为类似于普通的Python文件对象,所以在你读取它一次之后(用于制作第一个缩略图),你已经到达了文件的末尾,因此当你再次尝试读取它(制作第二个缩略图)时,就没有内容可读了,从而导致了IOError。要制作第二个缩略图,你需要将文件指针回到文件开头。因此,你可以添加以下代码:

image.seek(0)

将其添加到您的image_resizer函数的开头。

但是这是不必要的!您遇到了这个问题,是因为每次想要创建新缩略图时都在请求Python Imaging Library重新读取图像。这是浪费时间的:最好只读取一次图像,然后创建所有所需的缩略图。


谢谢您的清晰解释!是的,该图像由远程用户上传,并且其类型为<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>。现在我明白了IOError,我将重写我的代码以仅读取一次图像! - enri

-2

我猜这是一个TemporaryUploadedFile...可以通过type(image)找到它。

import cStringIO

if isinstance(image, TemporaryUploadedFile):
    temp_file = open(image.temporary_file_path(), 'rb+')
    content = cStringIO.StringIO(temp_file.read())
    image = Image.open(content)
    temp_file.close()

我不完全确定上面的代码……来自我用于图像处理的两个类……但可以试一下。

如果是一个InMemoryUploadedFile,你的代码应该可以工作!


谢谢帮助(我发现了cStringIO)!我解决了批量创建不同图片的问题,这样我只需要打开一次图像。 - enri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接