Issue
Context: I'm creating a chat app in Django, when the user sends an image to a chat the image data get encoded into base 64 (using btoa() javascript func) and get sent to the server so the server could create a new message and store it in the database.
This is my model:
class Message(models.Model):
sender_user = models.ForeignKey(User, on_delete=models.CASCADE)
text = models.TextField(blank=False, null=False)
image = models.ImageField(blank=True, null=True, upload_to='messages/')
date = models.DateTimeField(default=timezone.now)
chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.text
Problem: Whenever I use a decoded (base 64) image data as the content in the ContentFile class the content seems to be corrupted and the result image in the database can't be opened by any program.
This is the code
def create_message(
self,
sender_user_id: Union[str, int],
text: str,
image: Optional[str],
chat_id: Union[str, int],
) -> None:
"""Creates and stores a new message object in the database.
Args:
sender_user_id (Union[str, int]): The id (numeric value) of the user that sent the message.
text (str): What the message says.
image (str): The encoded image data in base64 encoding.
chat_id (Union[str, int]): The id (numeric value) of the chat that the sender sent this message on.
"""
sender_user_instance = User.objects.get(id=sender_user_id)
chat_instance = Chat.objects.get(id=chat_id)
new_message = Message.objects.create(
sender_user=sender_user_instance,
text=text,
date=timezone.now(),
chat=chat_instance,
)
if image != "":
image_bytes_data = base64.b64decode(image)
# removes the prefix data:image/jpeg;base64 from the decoded bytes
image_prefix, image_bytes = image_bytes_data.split(b",", 1)
# print(image == base64.b64encode(image_bytes_data)) prints False
# print(image_bytes_data == base64.b64decode(base64.b64encode(image_bytes_data))) prints True
# Check image type
image_type = imghdr.what(BytesIO(image_bytes_data))
if image_type not in ["jpeg", "png", "gif"]:
# Handle invalid image type
print(f"Invalid image type: {image_type}")
image_file = ContentFile(image_bytes, f"user_message.{image_type}")
new_message.image = image_file
new_message.save()
I checked the image type with the code above and it always returned me None no matter what although I tested the image_bytes_data value pasting it into a webpage base64 to image converter, the image loads without any problem and even tell me that is it a .JPEG image or .PNG.
I tried removing the prefix data:image/jpeg;base64 from the image_bytes_data bytes, again, I used the webpage tool and it showed me the image but the stored image in Django can't be opened and seems corrupted.
Solution
You're trying to remove the prefix data:image/jpeg;base64,
after decoding the base64 string, which is not correct. The prefix should be removed before decoding the base64 string.
Modify your code:
if image != "":
# Split the 'data:' scheme and comma at the end of the header
file_format, imgstr = image.split(';base64,')
# Get the file format (png, jpg, jpeg, etc.)
ext = file_format.split('/')[-1]
# Decode the base64 image data
data = ContentFile(base64.b64decode(imgstr), name='temp.' + ext)
new_message.image = data
new_message.save()
Answered By - godd0t
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.