Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 尝试在django中创建缩略图时,获取无法识别图像文件_Python_Django_Python Imaging Library - Fatal编程技术网

Python 尝试在django中创建缩略图时,获取无法识别图像文件

Python 尝试在django中创建缩略图时,获取无法识别图像文件,python,django,python-imaging-library,Python,Django,Python Imaging Library,可能重复: 我试图在django中创建一个缩略图,我试图构建一个专门用于生成缩略图的自定义类。如下 from cStringIO import StringIO from PIL import Image class Thumbnail(object): SIZE = (50, 50) def __init__(self, source): self.source = source self.output = None def g

可能重复:

我试图在django中创建一个缩略图,我试图构建一个专门用于生成缩略图的自定义类。如下

from cStringIO import StringIO
from PIL import Image

class Thumbnail(object):

    SIZE = (50, 50)

    def __init__(self, source):
        self.source = source
        self.output = None

    def generate(self, size=None, fit=True):
        if not size:
            size = self.SIZE

        if not isinstance(size, tuple):
            raise TypeError('Thumbnail class: The size parameter must be an instance of a tuple.')

        # resize properties
        box = size
        factor = 1
        image = Image.open(self.source)
        # Convert to RGB if necessary
        if image.mode not in ('L', 'RGB'): 
            image = image.convert('RGB')
        while image.size[0]/factor > 2*box[0] and image.size[1]*2/factor > 2*box[1]:
            factor *=2
        if factor > 1:
            image.thumbnail((image.size[0]/factor, image.size[1]/factor), Image.NEAREST)

        #calculate the cropping box and get the cropped part
        if fit:
            x1 = y1 = 0
            x2, y2 = image.size
            wRatio = 1.0 * x2/box[0]
            hRatio = 1.0 * y2/box[1]
            if hRatio > wRatio:
                y1 = int(y2/2-box[1]*wRatio/2)
                y2 = int(y2/2+box[1]*wRatio/2)
            else:
                x1 = int(x2/2-box[0]*hRatio/2)
                x2 = int(x2/2+box[0]*hRatio/2)
            image = image.crop((x1,y1,x2,y2))

        #Resize the image with best quality algorithm ANTI-ALIAS
        image.thumbnail(box, Image.ANTIALIAS)

        # save image to memory
        temp_handle = StringIO()
        image.save(temp_handle, 'png')
        temp_handle.seek(0)

        self.output = temp_handle

        return self

    def get_output(self):
        self.output.seek(0)
        return self.output.read()
这个类的目的是让我可以在不同的位置使用它来动态生成缩略图。这个类工作得很好,我已经在视图下直接测试了它。。我在表单的save方法中实现了缩略图类,以便在保存时调整原始图像的大小

在我的设计中,我有两个缩略图字段。我能够生成一个缩略图,如果我尝试生成两个缩略图,它会崩溃,我已经被困了几个小时,不知道是什么问题

这是我的模型

class Image(models.Model):
    article         = models.ForeignKey(Article)
    title           = models.CharField(max_length=100, null=True, blank=True)
    src             = models.ImageField(upload_to='publication/image/')
    r128            = models.ImageField(upload_to='publication/image/128/', blank=True, null=True)
    r200            = models.ImageField(upload_to='publication/image/200/', blank=True, null=True)

    uploaded_at     = models.DateTimeField(auto_now=True)
这是我的表格

class ImageForm(models.ModelForm):
    """

    """
    class Meta:
        model = Image
        fields = ('src',)


    def save(self, commit=True):
        instance = super(ImageForm, self).save(commit=True)


        instance.r128 = SimpleUploadedFile(
                    instance.src.name,
                    Thumbnail(instance.src).generate((128, 128)).get_output(),
                    content_type='image/png'
                )


        instance.r200 = SimpleUploadedFile(
            instance.src.name,
            Thumbnail(instance.src).generate((200, 200)).get_output(),
            content_type='image/png'
        )

        if commit:
            instance.save()
        return instance
奇怪的是,当我删除表单save中包含instance.r200的行时。它工作得很好,并且可以成功地生成缩略图并存储。一旦我添加了第二个缩略图,它就会失败

你知道我做错了什么吗

谢谢

更新:

根据注释请求,我将附加错误跟踪

IOError at /en/publication/new/

cannot identify image file

Request Method:     POST
Request URL:    http://127.0.0.1:8000/en/publication/new/?image-extra=
Django Version:     1.4.2
Exception Type:     IOError
Exception Value:    

cannot identify image file

Exception Location:     /Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py in open, line 1980
Python Executable:  /Users/mo/Projects/pythonic/snowflake-env/bin/python
Python Version:     2.7.2
更新

试图创建打印语句,下面是输出

Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
    return func(*args, **kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
    formset.save()
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
    return self.save_existing_objects(commit) + self.save_new_objects(commit)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
    self.new_objects.append(self.save_new(form, commit=commit))
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
    obj = form.save(commit=False)
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
    Thumbnail(instance.src).generate((200, 200)).get_output(),
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 23, in generate
    image = Image.open(self.source)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
    raise IOError("cannot identify image file")
IOError: cannot identify image file
如图所示,第一个图像打印和处理成功,第二个图像失败

更新

在缩略图类中应用副本后的回溯错误更新

ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
    return func(*args, **kwargs)
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
    formset.save()
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
    return self.save_existing_objects(commit) + self.save_new_objects(commit)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
    self.new_objects.append(self.save_new(form, commit=commit))
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
    obj = form.save(commit=False)
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
    f128.write(Thumbnail(instance.src).generate((128, 128)).get_output())
  File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 15, in __init__
    self._pilImage = Image.open(self.source)
  File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
    raise IOError("cannot identify image file")
IOError: cannot identify image file
更新

最后,我设法让它工作,但我不得不将文件作为belo流式传输到self.source

def __init__(self, source):
    self.source = StringIO(file(source.path, "rb").read())
    self.output = None

    self._pilImage = Image.open(self.source)

上述方法是否理想?每次点击时读取文件是个好主意吗?如果没有,我的选择是什么?

我看到的问题是您设计缩略图类的方式。它使用类属性来存储实例变量,这意味着当您尝试多次使用该类时,会发生冲突

不需要静态加载方法,因为一旦您将属性移动到实例,它将执行与类的构造函数完全相同的操作。通过在构造函数中要求一个源,可以确保在generate中查找空字符串值时不会发生崩溃

另外,我认为您面临的一个主要问题是,当您使用django模型为ImageField返回的类似文件的对象包装器时。虽然在传递字符串路径时不会看到这一点,但在传递file对象时,generate方法会将其读取到底。然后,使用同一个源对象再次调用generate,但是在最后,您得到了一个IOError。现在,一种方法是确保在再次调用Thumbnail之前将源代码搜索回0,但是您可以省去麻烦,只需打开Thumbnail类并在构造函数中缓存一次PIL映像。然后生成不需要每次都不断地重新读取它

# Example from your code #
def generate(self, size=None, fit=True):
    ...
    # The first time you do this, it will read
    # self.source to the end, because in Django, you
    # are passing a file-like object.
    image = Image.open(self.source)

# this will work the first time
generate()
# uh oh. self.source was a file object that is at the end
generate() # crash
重写缩略图类

用法:Thumbnailsrc.generate200、200.get\u输出

每个实例的源和输出都必须是唯一的。但在您的版本中,您会将输出设置为类级别,这意味着缩略图的两个实例使用共享的最新版本的输出

另外,我觉得有一种更简单的方法来执行调整大小/贴合/裁剪。如果你解释了你想要对图像做的精确变换,我可能也可以简化它

更新

我忘了特别提到,根据我关于保存源映像一次的建议,您的用法应该如下所示:

def save(self, commit=True):
    instance = super(ImageForm, self).save(commit=True)

    thumb = Thumbnail(instance.src)

    instance.r128 = SimpleUploadedFile(
        instance.src.name,
        thumb.generate((128, 128)).get_output(),
        content_type='image/png'
    )

    instance.r200 = SimpleUploadedFile(
        instance.src.name,
        thumb.generate((200, 200)).get_output(),
        content_type='image/png'
    )

请注意,我们仅使用源代码创建一个缩略图实例,它将在PIL中仅打开一次。然后,您可以根据需要生成任意多的图像。

我看到的问题在于您设计缩略图类的方式。它使用类属性来存储实例变量,这意味着当您尝试多次使用该类时,会发生冲突

不需要静态加载方法,因为一旦您将属性移动到实例,它将执行与类的构造函数完全相同的操作。通过在构造函数中要求一个源,可以确保在generate中查找空字符串值时不会发生崩溃

另外,我认为您面临的一个主要问题是,当您使用django模型为ImageField返回的类似文件的对象包装器时。虽然在传递字符串路径时不会看到这一点,但在传递file对象时,generate方法会将其读取到底。然后,使用同一个源对象再次调用generate,但是在最后,您得到了一个IOError。现在,一种方法是确保在再次调用Thumbnail之前将源代码搜索回0,但是您可以省去麻烦,只需打开Thumbnail类并在构造函数中缓存一次PIL映像。然后生成不需要每次都不断地重新读取它

# Example from your code #
def generate(self, size=None, fit=True):
    ...
    # The first time you do this, it will read
    # self.source to the end, because in Django, you
    # are passing a file-like object.
    image = Image.open(self.source)

# this will work the first time
generate()
# uh oh. self.source was a file object that is at the end
generate() # crash
重写缩略图类

< p> 用法:Thumbnailsrc.generate200、200.get\u输出

每个实例的源和输出都必须是唯一的。但在您的版本中,您会将输出设置为类级别,这意味着缩略图的两个实例使用共享的最新版本的输出

另外,我觉得有一种更简单的方法来执行调整大小/贴合/裁剪。如果你解释了你想要对图像做的精确变换,我可能也可以简化它

更新

我忘了特别提到,根据我关于保存源映像一次的建议,您的用法应该如下所示:

def save(self, commit=True):
    instance = super(ImageForm, self).save(commit=True)

    thumb = Thumbnail(instance.src)

    instance.r128 = SimpleUploadedFile(
        instance.src.name,
        thumb.generate((128, 128)).get_output(),
        content_type='image/png'
    )

    instance.r200 = SimpleUploadedFile(
        instance.src.name,
        thumb.generate((200, 200)).get_output(),
        content_type='image/png'
    )
请注意,我们仅使用源代码创建一个缩略图实例,它将在PIL中仅打开一次。然后您可以根据需要从中生成任意多的图像。

PIL.Image.open的参数。。。可以是文件名或文件对象。如果使用类似文件的对象,则读取位置应位于文件的开头。使用文件对象。这是肯定的,因为您使用instance.src.name,然后传递Thumbnailinstance.src

解决方案:在创建第二个缩略图之前,按instance.src.seek0将文件倒带到开头,或者只传递文件名,而不传递文件对象:Thumbnailinstance.src.name。

PIL.Image.open的参数。。。可以是文件名或文件对象。如果使用类似文件的对象,则读取位置应位于文件的开头。使用文件对象。这是肯定的,因为您使用instance.src.name,然后传递Thumbnailinstance.src



解决方案:在创建第二个缩略图或仅传递文件名之前,按instance.src.seek0将文件倒带到开头,不是文件对象:Thumbnailinstance.src.name。

p.S错误是无法识别图像文件是否有不使用的原因?我不使用stdimage的原因是因为我裁剪图像而不仅仅是重新缩放。。我不知道复制的原因,我认为这与缩略图类有关。你的类写得很奇怪。另外,包括您的回溯。我刚刚将回溯添加到帖子中。得到的错误是无法识别图像文件是否有您不使用的原因?我不使用stdimage的原因是因为我裁剪图像,而不仅仅是重新缩放。。我不知道复制的原因,我认为这与缩略图类有关。你的类写得很奇怪。另外,包括您的tracebacki刚刚附加到文章的tracebackHi jdi,非常感谢您的详细解释,我感谢您花费的时间。然而,我仍然面临着同样的错误,我复制了与您建议的完全相同的代码,但问题是相同的。我开始怀疑问题来自forms.save方法。通过查看它,您认为这可能是问题所在吗?我之所以怀疑forms.save方法,是因为我刚刚尝试在视图中使用缩略图类来呈现带有图像的HttpResponse,并将其指定为png的memtype。我试着生成两个和三个缩略图,然后只重新运行最后一个,结果成功了。那么,这不是意味着forms.save或模型不被接受吗?我只是用我使用的最新代码更新了这个问题,并且出现了回溯错误。你能帮我一个忙,在这行前面放一条打印语句吗Image.openself.source,在你的缩略图类中:print source:,self.source。我很好奇你到底在传递什么给PILI我做了印刷,我得到了以下来源:publication/image/1207281205471202-tonylawfirmpic_33.jpgHi jdi,非常感谢你的详细解释,我感谢你花费的时间。然而,我仍然面临着同样的错误,我复制了与您建议的完全相同的代码,但问题是相同的。我开始怀疑问题来自forms.save方法。通过查看它,您认为这可能是问题所在吗?我之所以怀疑forms.save方法,是因为我刚刚尝试在视图中使用缩略图类来呈现带有图像的HttpResponse,并将其指定为png的memtype。我试着生成两个和三个缩略图,然后只重新运行最后一个,结果成功了。那么,这不是意味着forms.save或模型不被接受吗?我只是用我使用的最新代码更新了这个问题,并且出现了回溯错误。你能帮我一个忙,在这行前面放一条打印语句吗Image.openself.source,在你的缩略图类中:print source:,self.source。我很好奇你到底在传递什么给PILI我做了印刷,我得到了以下来源:publication/image/1207281205471202-tonylawfirmpic_33.jpg