P5 Upload Image
Last week I was trying to make a file uploader, to then bring the image into P5.
The process (geddit?!) was a little different to what I expected, and thanks to David Aerne for showing me the solution!
The issue
At first, I tried what would seem natural, coming from the angle of typical DOM and JavaScript APIs.
In the HTML, I had something like the following.
<input type="file" id="inputEl" />
And then in the JavaScript.
let img;
let el = document.getElementById("inputEl");
el.addEventListener("change", (e) => {
img = URL.createObjectURL(e.target.files[0]);
});
function setup() {
createCanvas(500, 500);
}
function draw() {
background(255);
if (img) {
image(img, 0, 0, width, height);
}
}
This looks like it makes sense to me. We set up an img
variable that's going to either be undefined, and not be rendered. Or, it will contain image data and be displayed.
However, this doesnt work! We get the error Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'
. This was really confusing to me. I tried creating <img>
elements and all sorts of things to try and turn that data image string into one of these valid formats.
After some chat with David he explained that with p5 we need to come at the issue a different way.
The Solution
Here is the actual JS that works (no HTML needed). In fact, p5 has a file input API in it, for this exact scenario.
let input;
let img;
function setup() {
createCanvas(500, 500);
input = createFileInput(handleFile);
}
function draw() {
background(255);
if (img) {
image(img, 0, 0, width, height);
}
}
function handleFile(file) {
print(file);
if (file.type === "image") {
img = createImg(file.data, "");
img.hide();
} else {
img = null;
}
}
This feels really counterintuitive to me, but it all makes sense when you think about the p5 lifecycle.
P5 starts to exist in the setup()
function. This seems to be the main key. We let p5 create the input, rather than doing it with regular HTML. This means p5 is completely aware of the input, and can put it's own listeners on there to work with it's lifecycle.
The handleFile()
callback is creating an image and then hides it. But it's now available to us to use in the context of p5.
Then finally, in the drawFunction, we're ready to go and show the image!
If you enjoyed this article, sign up here to get new articles whisked straight to your inbox!