Last active
April 14, 2020 18:31
-
-
Save rafaelgontijo/c6260ea08a69a65cfdf6bece437a6e4b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import imghdr | |
| import io | |
| import base64 | |
| import binascii | |
| import uuid | |
| from django.core.exceptions import ValidationError | |
| from django.core.files.base import ContentFile | |
| from django.utils.translation import gettext_lazy as _ | |
| from rest_framework.fields import CharField | |
| class Base64ImageFieldMixin(object): | |
| @property | |
| def INVALID_FILE_MESSAGE(self): | |
| return _("") | |
| EMPTY_VALUES = (None, '', [], (), {}) | |
| def __init__(self, *args, **kwargs): | |
| self.represent_in_base64 = kwargs.pop('represent_in_base64', False) | |
| super(Base64FieldMixin, self).__init__(*args, **kwargs) | |
| def to_internal_value(self, base64_data): | |
| # Check if this is a base64 string | |
| if base64_data in self.EMPTY_VALUES: | |
| return None | |
| if isinstance(base64_data, string_types): | |
| # Strip base64 header. | |
| if ';base64,' in base64_data: | |
| header, base64_data = base64_data.split(';base64,') | |
| # Try to decode the file. Return validation error if it fails. | |
| try: | |
| decoded_file = base64.b64decode(base64_data) | |
| except (TypeError, binascii.Error, ValueError): | |
| raise ValidationError(self.INVALID_FILE_MESSAGE) | |
| # Generate file name: | |
| file_name = self.get_file_name(decoded_file) | |
| # Get the file name extension: | |
| file_extension = self.get_file_extension(file_name, decoded_file) | |
| complete_file_name = file_name + "." + file_extension | |
| data = ContentFile(decoded_file, name=complete_file_name) | |
| return super(Base64FieldMixin, self).to_internal_value(data) | |
| raise ValidationError(_('Invalid type. This is not an base64 string: {}'.format( | |
| type(base64_data)))) | |
| def get_file_extension(self, filename, decoded_file): | |
| try: | |
| from PIL import Image | |
| except ImportError: | |
| raise ImportError("Pillow is not installed.") | |
| extension = imghdr.what(filename, decoded_file) | |
| # Try with PIL as fallback if format not detected due | |
| # to bug in imghdr https://bugs.python.org/issue16512 | |
| if extension is None: | |
| try: | |
| image = Image.open(io.BytesIO(decoded_file)) | |
| except (OSError, IOError): | |
| raise ValidationError(self.INVALID_FILE_MESSAGE) | |
| extension = image.format.lower() | |
| extension = "jpg" if extension == "jpeg" else extension | |
| return extension | |
| def get_file_name(self, decoded_file): | |
| return str(uuid.uuid4()) | |
| class ImageBase64S3(Base64ImageFieldMixin, CharField): | |
| def to_internal_value(self, base64_data): | |
| file = super(ImageBase64S3, self).(base64_data) | |
| upload_service = SgpFileStorageSingleton() | |
| file_name = self.get_file_name(decoded_file) | |
| file_extension = self.get_file_extension(file_name, decoded_file) | |
| complete_file_name = file_name + "." + file_extension | |
| return upload_service.upload_file_stream(complete_file_name, file, private=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment