pythondjangopython-imaging-librarydjango-imagekit

I/O operation on closed file: Django Imagekit & Pillow


I am using django imagekit and pillow to upload images which was working fine in django 1.7. Recently we shifted to django 1.10 and now the image upload is not working. Code snippet is:

class Images(models.Model):
    image = ProcessedImageField(upload_to='main',
                                processors=[ResizeToCover(640, 640)],
                                format='JPEG',
                                options={'quality': 90})
    image_thumbnail = ProcessedImageField(upload_to='thumbnails',
                                          processors=[SmartResize(128, 128)],
                                          format='JPEG',
                                          options={'quality': 70})
    user = models.ForeignKey(User)

    def upload_image(self, image, user):
        if len(image.name) > 30:
            image.name = image.name[:20]
        i = Images.objects.create(image=image, image_thumbnail=image, user=user)
        return i

The traceback is:

File "C:\Python35\lib\site-packages\imagekit\specs\__init__.py" in generate
  149.             img = open_image(self.source)

File "C:\Python35\lib\site-packages\pilkit\utils.py" in open_image
  21.     target.seek(0)

During handling of the above exception (I/O operation on closed file.), another exception occurred:

File "C:\Python35\lib\site-packages\django\core\handlers\exception.py" in inner
  39.             response = get_response(request)

File "C:\Python35\lib\site-packages\django\core\handlers\base.py" in _legacy_get_response
  249.             response = self._get_response(request)

File "C:\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "C:\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Python35\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "C:\Users\sp\industryo\nodes\views.py" in set_logo
  173.             i = Images.objects.create(image=image, user=user, image_thumbnail=image)

File "C:\Python35\lib\site-packages\django\db\models\manager.py" in manager_method
  85.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Python35\lib\site-packages\django\db\models\query.py" in create
  399.         obj.save(force_insert=True, using=self.db)

File "C:\Python35\lib\site-packages\django\db\models\base.py" in save
  796.                        force_update=force_update, update_fields=update_fields)

File "C:\Python35\lib\site-packages\django\db\models\base.py" in save_base
  824.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

File "C:\Python35\lib\site-packages\django\db\models\base.py" in _save_table
  908.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "C:\Python35\lib\site-packages\django\db\models\base.py" in _do_insert
  947.                                using=using, raw=raw)

File "C:\Python35\lib\site-packages\django\db\models\manager.py" in manager_method
  85.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Python35\lib\site-packages\django\db\models\query.py" in _insert
  1043.         return query.get_compiler(using=using).execute_sql(return_id)

File "C:\Python35\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
  1053.             for sql, params in self.as_sql():

File "C:\Python35\lib\site-packages\django\db\models\sql\compiler.py" in as_sql
  1006.                 for obj in self.query.objs

File "C:\Python35\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
  1006.                 for obj in self.query.objs

File "C:\Python35\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
  1005.                 [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]

File "C:\Python35\lib\site-packages\django\db\models\sql\compiler.py" in pre_save_val
  955.         return field.pre_save(obj, add=True)

File "C:\Python35\lib\site-packages\django\db\models\fields\files.py" in pre_save
  292.             file.save(file.name, file, save=False)

File "C:\Python35\lib\site-packages\imagekit\models\fields\files.py" in save
  12.         content = generate(spec)

File "C:\Python35\lib\site-packages\imagekit\utils.py" in generate
  134.     content = generator.generate()

File "C:\Python35\lib\site-packages\imagekit\specs\__init__.py" in generate
  153.             self.source.open()

File "C:\Python35\lib\site-packages\django\db\models\fields\files.py" in open
  81.         self.file.open(mode)

File "C:\Python35\lib\site-packages\django\core\files\uploadedfile.py" in open
  96.         self.file.seek(0)

Exception Type: ValueError at /nodes/set_logo/
Exception Value: I/O operation on closed file.

What can be done here. Do i need to make changes in the packages? Help!


Solution

  • It seems that Imagekit and Pillow are not interacting very well in latest release. The Problem as it can be seen was happening because the file sent by imagekit could not be processed directly by PIL.

    So for cropping and changing size and quality, we shifted entirely to PIL.

    def upload_image1(self, image, user, name, image1):
    
            if len(image1.name) > 30:
                image1.name = image1.name[:20]
            i = Images.objects.create(image=image1, user=user)
            new_image_io = BytesIO()
            image.save(new_image_io, format='JPEG')
            i.image_thumbnail.save(name, content=ContentFile(new_image_io.getvalue()))
            return i
    

    To Create the thumbnail, we had to open the image and save it as here:

    new_image_io = BytesIO()
    image.save(new_image_io, format='JPEG')
    i.image_thumbnail.save(name, content=ContentFile(new_image_io.getvalue()))
    

    Hope it helps!