The other day, i was with a friend and after a few beers, the idea of resizing every cell to a 1x1 pixel size in an excel file and styling its background to match a pixel in an image came out. Loving to make apps and script without any sense, i decided to make a web app who would do it. So this post is going to be about its making.
You can use it right now from your browser here and this is what you get using the classical lenna image (i like showing the final product first)
In this post we’re going to use the following Apis, you only need to know the basics
First of all, we are going to make an input to select our image, and include our js file and a little modified version of JS-xlsx
Now, in our app.js file, first we are going to get a reference to our input and create a new instance of our WebWorker
Then we are going to listen for the change event in our input, get its first file, and call our makeCanvas function which will return a promise with a canvas with the image drawn on it. Then we are going to pass the imageData of our canvas into our WebWorker
Now here is where all the magic happens, first we need to create a new file called worker.js. There we are going to make two functions which will help us convert colors from rgb to hex and import our js-xlsx file
Then we are going to attach a function to be executed everytime we get data into our webworker.
The following code is going to be inside in our onmessage function, i’ve stripped it to explain it piece by piece
First of all, we get our imageData passed, which is a flatten array, and convert it to an array of objects with its rgba values separated
Now we need to make our spreadsheet object. To do this, first we are going to figure out in wich row and column we are. Then we convert this to a valid cell id, and set it as the key in our object and its value to a style with our pixel color as background. The “official” version of js-xlsx doesnt allow custom styles to be set, so i have to use protobi’s version
Now we need to set our range of cells, and set the column width to be 1px. As neither of two allow us to set our row height, i have to edit the file and set it manually, so no step for this. We also need to make our workbook object, which is going to be written.
Finally, we write our wokbook, create a blob for it and a url which is going to be passed to our main thread.
Our final step is to handle our data back from the worker so in our app.js file we need to listen for the onmessage event. What we are only doing here is creating a new a tag with the url to our workbook’s blob and appending it to the body.
And thats all the magic you need to know!
PD: Yes, i know i could use Service Workers to make it a fully operational web app, but thats not the point of the post
PD II: Yes, i also know that i could use webworkers in previous posts, but i dont know why i didnt