user5854440 user5854440 - 1 year ago 189
Javascript Question

JavaScript: Error from converting user inputed image to base64

Trying to store user image to server. Very new to this, so I just started looking around and I found the following code:

function getBase64Image( imgElem ) {

let canvas = document.createElement( 'canvas' );
canvas.width = imgElem.clientWidth;
canvas.height = imgElem.clientHeight;

let ctx = canvas.getContext( '2d' );
ctx.drawImage(imgElem, 0, 0);

let dataURL = canvas.toDataURL( 'image/png' );
return dataURL.replace( /^data:image\/(png|jpg);base64,/, '' );


I'm using this function to store a user inputed image on my local server, but I get the following error:

factories.js:1 Uncaught TypeError: Failed to execute 'drawImage' on
'CanvasRenderingContext2D': The provided value is not of type
'(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or
ImageBitmap)'getBase64Image @ factories.js:1SubmitRecipe @
recipe-submission.js:1onclick @ submitrecipe:43

I am grabbing the image with an input tag that has
set to
. Here is my code:


<span class='err-message' id='image-err'></span></br>
<input type="file" id='image'>


function SubmitRecipe() {

//sets the recipe object and its keys
let recipe = { alias: null, description: null, category: null, instructions: null, image: null };

let img = document.getElementById( 'image' );
recipe.image = JSON.stringify( getBase64Image( img ) );


I believe the problem has to do with the fact that the element
is an
, and that isn't what
expects. I just have no idea how to solve it.

All help is appreciated.

Answer Source

You can make use of the FileReader object to do this. The really neat thing is it can even give us the data as a data URL in the first place - this means we dont convert/recompress images in the process. A jpg wont be enlarged by saving as a png, nor will a png lose detail by conversion to a jpg. Since we're no longer using the canvas to create the URL, we no longer have control over the precise mime-type. As such, we may have a jpg,png or jpeg file - this just means adding |jpeg to the regex so we replace instances of it too.

You can also listen to the change event of the file input. Doing so will allow you to check the size and type of file to ensure they are acceptable. (Someone could select a 100MB text file using the file input)

function byId(id){return document.getElementById(id)}
function newEl(tagName){return document.createElement(tagName)}

window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
	byId('goBtn').addEventListener('click', onBtnClicked, false);

function onBtnClicked(evt)
	let imgInput = byId('imageInput');
	let chosenFile = imgInput.files[0];
	let fr = new FileReader();
	fr.onload = function(evt)
                    var img = newEl('img');
                    img.src = this.result;
					var dataURL = this.result.replace( /^data:image\/(png|jpg|jpeg);base64,/, '' );
					let recipe = { alias: null, description: null, category: null, instructions: null, image: JSON.stringify(dataURL) };
	<span class='err-message' id='image-err'></span></br>
	<input type="file" id='imageInput'>
	<button id='goBtn'>GO</button>