简体   繁体   中英

Load an html5 canvas into a PIL Image with Django

I'm trying to get the contents of an html5 canvas and pass it to my django server, where it will then be manipulated with PIL and saved as a PNG. Here's what I have so far:

From the HTML form, the user clicks the "update" button, the canvas's contents - with canvas.toDataURL() - gets dumped into a text box that is submitted via a POST form. Eventually this will be automatic, but not for now.

<input type="text" id="canvasData" name="canvasData"/>
<input type='button' value="update" onclick='jscript:updateData();'>
<canvas id="sketch"></canvas>
<script type="text/javascript">
    function jscript:updateData() {
        $('#canvasData')[0].value = $('canvas')[0].toDataURL();
    }
</script>

The canvasData is in the form of 'data:image/png;base64,iVBORw0KGgoAAAA...etc...=' when it gets sent over. Then I deal with it in django:

from PIL import Image
...
canvasData = request.POST.get('canvasData', '')
im = Image.somehowLoad(canvasData)
...
im.save('canvas.png')

And this is where i'm stuck. I can't figure out how to get the base64-encoded data url to load up the image into a usable form with PIL.

Thanks!

edit: here's the code for the bottom comment:

>>> d
'data:image/png;base64,iVBORw0K'
>>> d.strip('data:image/png;base64,')
'VBORw0K'
import re

datauri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='

imgstr = re.search(r'base64,(.*)', datauri).group(1)

output = open('output.png', 'wb')

output.write(imgstr.decode('base64'))

output.close()

or if you need to load it into PIL :

import cStringIO

tempimg = cStringIO.StringIO(imgstr.decode('base64'))

im = Image.open(tempimg)

HTML:

<form action="" method="post">
    {% csrf_token %}
    <input type="hidden" name="width" value="">
    <input type="hidden" name="height" value="">
    <input type="hidden" name="image_data" value="">
</form>

Javascript:

function submit_pixels(canvas) {
    $('form input[name=image_data]').val(canvas.toDataURL("image/png"));
    $('form input[name=width]').val(canvas.width);
    $('form input[name=height]').val(canvas.height);
    $('form').submit();
}

Django POST Request View:

# in the module scope
from io import BytesIO
from PIL import Image
import re
import base64

# in your view function
image_data = request.POST['image_data']
image_width = int(request.POST['width'])
image_height = int(request.POST['height'])
image_data = re.sub("^data:image/png;base64,", "", image_data)
image_data = base64.b64decode(image_data)
image_data = BytesIO(image_data)
im = Image.open(image_data)
assert (image_width, image_height,) == im.size

Bump up the maximum POST size in your settings (example: ~20 MB):

# canvas data urls are large
DATA_UPLOAD_MAX_MEMORY_SIZE = 20_000_000

In 2019 with python3 i tried Acorn answer, and i got Error 'str' object has no attribute 'decode ' So i did some searching and adjusted the code and it worked here it is

from binascii import a2b_base64
import re

datauri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='

imgstr = re.search(r'base64,(.*)', datauri).group(1)

binary_data = a2b_base64(imgstr)

Out = open('image.png', 'wb')
Out.write(binary_data)
Out.close()

For Django 3.0 and python 3.7 code in the html file (which are called templates in the django)

 <form method="POST" id="form1"> {% csrf_token %} <canvas id="camera--sensor"></canvas> <!-- Camera view --> <video id="camera--view" autoplay playsinline></video> <!-- Camera output --> <img src="//:0" alt="" id="camera--output" onclick="show()"> <!-- Camera trigger --> <input type="hidden" id="captured_image" name="captured_image"> <input id="upload_image" type="submit" onclick="save()" value="Upload the image"> </form>

in the javascript file

 var canvas; function save(){ canvas = document.getElementById('camera--sensor'); document.getElementById('captured_image').value = canvas.toDataURL('image/png'); }

in the views.py file for Django

def capture_image(request):
    if request.method=="POST":
        # print("-------",request.POST)
        if request.POST.get('captured_image'):
            captured_image = request.POST.get('captured_image')
            # imgstr = captured_image.decode('base64')
            imgstr = re.search('base64,(.*)', captured_image).group(1)
            imgstr = base64.b64decode(imgstr)
            # print(imgstr)
            tempimg = io.BytesIO(imgstr)

            im = Image.open(tempimg)

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