简体   繁体   中英

How do I save base64 image from html5 canvas as ImageField in Django?

On my form, I have an ImageField as well as a hidden CharField to accept an image as base64. When a user selects an image on the frontend form my JS script on the frontend auto resizes the image as a canvas then sets the generated dataUrl as the content for the CharField. I would like that when the form is submitted I can convert the base64 text to an image and override the saving of the original Image in the ImageField so that the decoded base64 image is saved in its place instead (filename and all).

I have followed several tutorials online which have helped me formulate the code below. I have overwritten the clean() function in my forms.py so that the base64 text is decoded into a PIL Image. Now I would like to set it in place of the actual ImageField's content so that it is saved and handled as if the base64 decoded image was the file sent in POST.

Other answers suggest saving the decoded base64 image manually using a with open() command but that approach opens other headaches. Especially since Django already handles image renaming if an image is submitted with a name that already exists. I would rather not have to remake the wheel for this. Replacing the ImageField file with the generated one just before save through Django's built-in methods seems like the best approach.

Is there any way my desired approach is feasible? I have not found any answers which attempt to handle this scenario without having to manually save the file myself and update the model afterward.

from PIL import Image
from io import BytesIO

import os
import sys
import re
import base64


    def clean(self):
        cleaned_data = super().clean()

        dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$')
        ImageData = cleaned_data.get("image_base64_text")
        ImageData = dataUrlPattern.match(ImageData).group(2)
        ogImg = cleaned_data.get("image")

        # If none or len 0, means illegal image data
        if (ImageData == None or len(ImageData) == 0):
            # PRINT ERROR MESSAGE HERE
            print('corrupt or illegal image data')

        # Decode the 64 bit string into 32 bit
        ImageData = base64.b64decode(ImageData)
        ImageData = Image.open(BytesIO(ImageData))

Define clean_image method in form and return an instance of InMemoryUploadedFile from clean method. Ps I encourage you to use pep8 style guideline s for variable naming and other things related to code style.

def clean_image(self):
    dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$')
    ImageData = self.cleaned_data.get("image_base64_text")
    ImageData = dataUrlPattern.match(ImageData).group(2)

    # If none or len 0, means illegal image data
    if (ImageData == None or len(ImageData) == 0):
        # PRINT ERROR MESSAGE HERE
        print('corrupt or illegal image data')

    # Decode the 64 bit string into 32 bit
    ImageData = base64.b64decode(ImageData)
    ImageData = Image.open(BytesIO(ImageData))


    return InMemoryUploadedFile(ImageData,
                            'ImageField', 'filename'),
                            'image/jpeg',
                            sys.getsizeof(output),
                            None)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM