Skip to content

Instantly share code, notes, and snippets.

@rafaelgontijo
Last active April 14, 2020 18:31
Show Gist options
  • Select an option

  • Save rafaelgontijo/c6260ea08a69a65cfdf6bece437a6e4b to your computer and use it in GitHub Desktop.

Select an option

Save rafaelgontijo/c6260ea08a69a65cfdf6bece437a6e4b to your computer and use it in GitHub Desktop.
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