Let's write an image converter in 20 lines of html+js
Tags: tutorial, html, javascript, codepen
Published: 2022-06-24 23:39:51

> For those who just wanna see the code, [it's on my codepen](https://codepen.io/ninofiliu/pen/WNMVgOW)

Out of all the things you can do with web APIs, my fav arena has got to be playing around with the [canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). It basically offers you a rectangle you can draw anything you like - whether it's a bunch of [colorful circles](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc) or a more exotic objects like a [video frame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame); along with utilities to read out the RGB values of the whole stuff.

One of its powerful features is [`toDataURL`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) that can export the current canvas image into the format of your choice, like `image/jpeg` or `image/png`, and we're gonna use it to write our converter.

Let's start off with some basic inputs to ask the user for an image and to specify the desired output format and compression rate. The `<img>` will be where we'll display our converted and compressed image:

```html
File: <input type="file" accept="image/*"><br>
Convert to: <input value="image/jpeg"><br>
Quality: <input type="number" min="0" max="1" step="0.01" value="0.9"><br>
<button>Convert</button><br>
<img>
```

Then the JS to get a handle on these element:

```js
const [fileInput, typeInput, qualityInput] = document.querySelectorAll('input');
const outImg = document.querySelector('img')
document.querySelector('button').addEventListener('click', async () => {
  // TODO
});
```

We can get a hold of the image uploaded by the user by looking up `fileInput.files` which contains a list of [`File`s](https://developer.mozilla.org/en-US/docs/Web/API/File) from which you can make a URL with [`URL.createObjectURL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)

```js
const [file] = fileInput.files;
if (!file) return alert('file required');
const srcImg = document.createElement('img');
srcImg.src = URL.createObjectURL(file);
```

Now we have an [`Image`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image) of whatever the user uploaded, but before we [draw it](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) on a canvas, we have to wait for it to load using [`.decode`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode). Note that we adjust the canvas dimensions to the image dimensions, else the picture is going to be cropped:

```js
await srcImg.decode();
const canvas = document.createElement('canvas');
canvas.width = srcImg.width;
canvas.height = srcImg.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(srcImg, 0, 0);
```

Now time to use this tiny function that actually exposes a lot of browser "intelligence" in terms of image formats:

```js
outImg.src = canvas.toDataURL(typeInput.value, +qualityInput.value);
```

And... voilà!

You now have a minimal image converter + compressor.

Hope you've learned something interesting about image web APIs today!