Question

I'm trying to draw an image inside a canvas element using a data URI. I'm using Django and passing a variable containing the base64 encoding of the photo to the template. In the past, I have used that like so:

<img src="data:image/jpg;base64, {{ photo_data }}">

This works fine. I now want to replace that with this:

<canvas id="canvas"></canvas>

and use javascript to draw the image in the canvas. I tried out the code from this answer:

var canvas = $('#canvas');
var ctx = canvas.getContext('2d');
var img = new Image;
$(img).load(function(){
    ctx.drawImage(img, 0, 0);
});
img.src = "data:image/jpg;base64, {{ photo_data }}"

This gives me the javascript error "SyntaxError: unterminated string literal" on the last line. I read that this error usually happens because of line breaks. Upon inspecting the page source it looks like there are line breaks in there:

enter image description here

So then I tried removing line breaks:

function removeBreaks(data){
    return data.replace(/(\r\n|\n|\r)/gm, "");
}

var photo_data = removeBreaks({{ photo_data }});

Now I'm getting a new error when I call removeBreaks. "SyntaxError: identifier starts immediately after numeric literal".

var photo_data = removeBreaks(/9j/4AAQSkZ...
----------------------------------^

Is there some sort of escaping I need to do, and if so how would I do it?

Update

I tried all of the suggestions from the comments and the answer. So far the thing that has come closest to working is doing

photo_data = json.dumps(<base64 encoded image file>)

on the Django side and

var photo_data = "{{ photo_data }}".replace(/&quot;/g,"");
img.src = "data:image/jpg;base64, " + photo_data;

on the Javascript side. The image doesn't show at all if I don't replace the &quot;s, and when I do remove them only the top third of the image shows. I tried resizing the canvas element, that doesn't seem to be the issue.

Update #2

Turns out the canvas size was the issue. Width and height of the canvas element need to be as big or bigger than the width and height of the image, which I wasn't setting when I created the Image object. Both the accepted answer and json.dumps (with the &quot; caveat) work to solve the original problem.

Was it helpful?

Solution

I do it like this:

img.src = "1234 ... 56789" + //
   "01234567 ... 7890" + //
   .....
   "67879878907890";

Some people I work with like to put the + on the front of the line, claiming its easier to read.

Assume you have the image data, base64 encoded in a string. A sort of pseudo C/Java/Javascript like language would have code something like this (since I don't know Python):

String image64 = ...
String output = "img.src = \"data:image/jpg;base64, ";

for (int i = 0; i < image64.length ; i += 100) {
    if (i > 0) {
        output += "\" + // \n    \"";
    }
    if (i + 100 < image64.length) {
        output += image64.substring(i, i+100);
    } else {
        output += image64.substring(i); // this gets the rest
    }
}
output += "\";\n";

Then you write the value of output to where ever you are putting your javascript.

Now a quick look a Django and Python stuff leads me to suspect it would look something like this in the template:

img.src = "data:image/jpg;base64, " + //
{% for line in photo_data_lines %}
    "{{ line }}" + //
{% endfor %}
    "";

But you'd have to set up the photo_data_lines array with 100 character chunks of the image data in each element beforehand. (Or however long you want the chunks.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top