Пример #1
0
    def to_python(self, data):
        """
        Checks that the file-upload field data contains a valid source file
        (GIF, JPG, PNG, WEBM, MP4, etc) using imageio plugins.
        """
        f = super(ThumbnailerExtField, self).to_python(data)
        if f is None:
            return None

        # Check filesize limit
        # Nginx client_max_body_size is 5MB
        if f.size > 5 * 1024 * 1024:
            raise ValidationError(self.error_messages['max_size'],
                                  code='max_size')

        from pathlib import PurePath

        # Check for file extension
        ext = PurePath(f.name).suffix
        if ext == '':
            raise ValidationError(self.error_messages['invalid_extension'],
                                  code='invalid_extension')

        # Get temporary file path or raw bytes
        if hasattr(data, 'temporary_file_path'):
            file = data.temporary_file_path()
        else:
            if hasattr(data, 'read'):
                file = BytesIO(data.read())
            else:
                file = BytesIO(data['content'])

        from PIL import Image
        from imageio import get_reader

        try:
            # Firstly try and recognise BytesIO
            file = get_reader(file)
            # Send data to PIL
            f.image = Image.fromarray(file.get_data(0))
            # Close the reader
            force_close_reader(file)
        except ValueError:
            # Create a local file
            with NamedTemporaryFile(suffix=ext) as n:
                for chunk in data.chunks():
                    n.write(chunk)
                try:
                    # Try and read from temporary file
                    file = get_reader(n.name)
                    # Send data to PIL
                    f.image = Image.fromarray(file.get_data(0))
                except OSError:
                    # FFmpeg cannot read video meta
                    # May be out of memory for a new reader (bug #48)
                    params = { 'file': f.name }
                    raise ValidationError(self.error_messages['corrupt_file'],
                                          code='corrupt_file',
                                          params=params)
                except Exception:
                    # imageio doesn't recognize it as an image.
                    params = { 'types': self.types }
                    raise ValidationError(self.error_messages['invalid_file'],
                                          code='invalid_file',
                                          params=params)
                finally:
                    # Close Named Tempoary File
                    n.close()
                    # Make sure any open reader is closed
                    force_close_reader(file)

        # Check if this format is enabled
        # See ``imageboard.settings`` for more information
        if file.format.name in formats.keys():
            # MIME type is not supported with imageio
            # Thus if the content type is not detected, it will remain as None
            f.content_type = Image.MIME.get(f.image.format)

            if hasattr(f, 'seek') and callable(f.seek):
                f.seek(0)

            return f
        else:
            params = { 'types': self.types }
            raise ValidationError(self.error_messages['unsupported'],
                                  code='unsupported',
                                  params=params)