Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I draw an image from the HTML5 File API on Canvas?

People also ask

Which built in HTML5 object is used to draw on the canvas?

The HTML <canvas> element is used to draw graphics, on the fly, via JavaScript. The <canvas> element is only a container for graphics. You must use JavaScript to actually draw the graphics.

How do I make an image HTML5?

HTML Images SyntaxThe <img> tag creates a holding space for the referenced image. The <img> tag is empty, it contains attributes only, and does not have a closing tag. The <img> tag has two required attributes: src - Specifies the path to the image.


You have a File instance which is not an image.

To get an image, use new Image(). The src needs to be an URL referencing to the selected File. You can use URL.createObjectURL to get an URL referencing to a Blob (a File is also a Blob): http://jsfiddle.net/t7mv6/86/.

var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image;
img.onload = function() {
    ctx.drawImage(img, 20,20);
    alert('the image is drawn');
}
img.src = URL.createObjectURL(e.target.files[0]);

Note: be sure to revoke the object url when you are done with it otherwise you'll leak memory. If you're not doing anything too crazy, you can just stick a URL.revokeObjectURL(img.src) in the img.onload function.

References:

  • https://developer.mozilla.org/en/DOM/File
  • http://html5demos.com/file-api

Live Example

function handleFiles(e) {
    var ctx = document.getElementById('canvas').getContext('2d');
    var url = URL.createObjectURL(e.target.files[0]);
    var img = new Image();
    img.onload = function() {
        ctx.drawImage(img, 20, 20);    
    }
    img.src = url;   
}

window.URL.createObjectUrldocs

You could also use the FileReader instead to create the object URL.

The FileReader has slightly better browser support.

The FileReader approach works in FF6 / Chrome. I'm not certain whether setting Img.src to a Blob is valid and cross-browser though.

Creating object urls is the correct way to do it.

Edit:

As mentioned in the commment window.URL support whilst offline seems unavailable in FF6/Chrome.


Here is a complete example (Fiddle) using FileReader (which has better browser support as mentioned by Raynos). In this example I also scale Canvas to fit the image.

In real life example you might scale the image to some maximum so that your form will not blow up ;-). Here is an example with scaling (Fiddle).

var URL = window.webkitURL || window.URL;

window.onload = function() {
    var input = document.getElementById('input');
    input.addEventListener('change', handleFiles, false);
    
    // set original canvas dimensions as max
    var canvas = document.getElementById('canvas');
    canvas.dataMaxWidth = canvas.width;
    canvas.dataMaxHeight = canvas.height;
}

function handleFiles(e) {
    var ctx = document.getElementById('canvas').getContext('2d');
    var reader  = new FileReader();
    var file = e.target.files[0];
    // load to image to get it's width/height
    var img = new Image();
    img.onload = function() {
        // setup scaled dimensions
        var scaled = getScaledDim(img, ctx.canvas.dataMaxWidth, ctx.canvas.dataMaxHeight);
        // scale canvas to image
        ctx.canvas.width = scaled.width;
        ctx.canvas.height = scaled.height;
        // draw image
        ctx.drawImage(img, 0, 0
            , ctx.canvas.width, ctx.canvas.height
        );
    }
    // this is to setup loading the image
    reader.onloadend = function () {
        img.src = reader.result;
    }
    // this is to read the file
    reader.readAsDataURL(file);
}

// returns scaled dimensions object
function getScaledDim(img, maxWidth, maxHeight) {
    var scaled = {
        ratio: img.width / img.height,
        width: img.width,
        height: img.height
    }
    if (scaled.width > maxWidth) {
        scaled.width = maxWidth;
        scaled.height = scaled.width / scaled.ratio;
    }
    if (scaled.height > maxHeight) {
        scaled.height = maxHeight;
        scaled.width = scaled.height / scaled.ratio;
    }
    return scaled;
}
canvas {
    border:1px solid black
}
<input type="file" id="input"/>
<div>
    <canvas width="400" height="300" id="canvas"/>
</div>