intro

Recently, I was working on a project where resources were scarce, much more scarce than the average startup trying to cut down on costs.

I was the frontend and backend developer for such a project. The project didn’t finish, so, unfortunately, I have no demo to provide. However, the code was that useful that I wanted to share it to othe people.

resize image in the frontend

Not resizing the images in the backend means that we will resize image in the frontend. We have to, there is no other end beside the frontend and the backend.

no client libraries

Most people know that the browser is a beast capable of handling different video formats and images formats.

Few people know that this same browser is also capable of manipulating images and videos. How? through internal Javascript APIs. No, there is no Image class that you could call resize or compress and you have a new image.

Instead, you have a canvas API that virtually all browsers support. You could import images to the canvas API, resize the image in the canvas and turn the canvas to a png.

just show me the code

Sure.

const resizeImage = (file : File|Blob|MediaSource, width : number, height : number) => {
	const c = document.createElement('canvas');
	c.width = width;
	c.height = height;

	const ctx = c.getContext('2d');

	let img = new Image();
	img.src = URL.createObjectURL(file);

	img.onload = () => {
		ctx.drawImage(img, 0, 0, width, height);
		console.log(c.toDataURL('image/webp'));
	};
}

Cool, eh? Basically, it creates a canvas with width and height, put an image inside that canvsa with that width and height, and lastly, it prints the canvas’s data image URL.

Now, if you want a blob, go get a blob through toBlob.

edge functions and stuff

vercel’s Edge Functions obviously don’t support this because they don’t support the DOM. Though, other vendors like Netlify could support something like this but I haven’t researched this.

how to do cachable base64 images

For my specific case, I had saved images in the form of base64 in my database. If the database was a git database, you could do text comparison or something similar.

I might revert to just storing it as a blob since it is less size. Regardless, here’s one little neat fact.

You can convert any base64 string to a blob through the fetch api. Just fetch the URL and call .blob() and voila, you have a blob:

export async stringToBlob(img : string) => {
	return (await (await fetch(image)).blob());
}

To cache stuff, use the following hash function that enables you to generate a SHA-256 hash sum of a string:

async function hash(str : string) {
	const utf8 = new TextEncoder().encode(str);
	const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
	const hashArray = Array.from(new Uint8Array(hashBuffer));
	const hashHex = hashArray
		.map((bytes) => bytes.toString(16).padStart(2, '0'))
		.join('');
	return hashHex;
}