I understand the current common technique for creating an <img />
element in JavaScript from a client-side File
object goes something like this.
(The File
object would originate from a file drag-and-drop handler or <input type="file" />
change
event.)
function showImageFile( file: File ): void {
let rdr = new FileReader();
rdr.readAsDataURL( file );
rdr.onloadend = function() {
let img = document.createElement('img');
img.src = rdr.result;
document.body.appendChild( img );
};
}
I don't like this - the notion of serialising what could be a multi-megabyte image to a base64-encoded string (thus using 1.3x more memory on top of the existing File
object) as well as incurring the cost of deserializing the string back into the <img />
element - ultimately this will cause at least 3 instances of the image's data to exist in memory. This seems very wasteful and inefficient to me, and JavaScript applications already have a bad rep for excessive memory consumption.
I noticed that for the <video>
and <audio>
elements (HTMLMediaElement
) that MDN recommends doing something like this:
function showVideoFile( file: File ): void {
let video = document.createElement('video');
video.srcObject = URL.createObjectURL( file ); // createObjectURL creates a URI alias to the existing file instance in-memory
}
(with the caveat that if srcObject
is ever replaced or the video
element removed, the previous objectURL
must be manually released using revokeObjectURL
.
Is there any way to do the same thing for <img />
? (I don't see a srcObject
property on HTMLImageElement
and HTMLImageElement
does not derive from HTMLMediaElement
). Searching online for "javascript image files without data URIs" unfortunately only returns pages about readAsDataURL
which is the opposite of what I want.
You set its… src
.
document.getElementById('file').onchange = function () {
if (this.files.length !== 0) {
var img = new Image();
img.src = URL.createObjectURL(this.files[0]);
document.body.appendChild(img);
}
};
<input type="file" id="file" accept="image/*" />