Re-Create an Image with Colorful Text
Published
Hey, friends! It’s been a while, but I’m back with something fun. Yesterday, I tweeted out about an image I analyzed and then re-created with my name. It’s garnered quite a bit of attention so I figured I’d tell everyone how I did it! It involves the HTML canvas
element and a little bit of looping over data from that to get information about the colors within the image. Let’s get started!
Quick note: There will be a CodeSandbox at the end of every step so you can follow along and check your work as you go.
1. Set up Your HTML & JS
This step is pretty boring. Nothing will be showing on the page after you’re done here. There are two main things to note:
- You only need to set the
crossorigin
attribute toAnonymous
if you’re working in a code sandbox. A security error comes up otherwise. - We can’t actually do anything with our image until it loads. Make sure all of the upcoming code is written within the
onload
event listener!
2. Draw Your Image on the canvas
Now that we have our image loaded and the canvas
on the page, we need to get the 2D rendering context for our canvas. We’ll call drawImage()
on the context and pass in three arguments:
- the image we want to draw
- the x coordinate to draw at
- the y coordinate to draw at
We only had to add two lines in this step. Your image should be showing up now! :)
3. Get the ImageData
We’re almost to the trickier part of this process, but first we need to get some data from the context. We put this in a try...catch
in case any thing goes wrong. For example, this is where you would see the security error from not setting the crossorigin
attribute of your image.
The getImageData()
function takes 4 arguments:
- x coordinate to start reading from
- y coordinate to start reading from
- width of area to read from
- height of area to read from
Note that we’re reading from the whole canvas because the image is pretty small and that’s how we set everything up. If you want to, you can draw a much bigger image on your canvas and then read data from a smaller area by modifying these 4 arguments.
4. Iterate to Get Pixel Colors
The ImageData
object we get in the previous has 3 properties: data
, width
, and height
. We’re interested in the first one. Here’s where things get a little weird. The data
property is a flat array. Not sure what that means? Here’s a quick example:
- A flat array:
["a", "b", "c", "d", ...]
- Not a flat array:
["a", "b", ["c", "d"], ...]
For each pixel of the data read from the context, there are 4 pieces of data pushed onto this array having to do with the color of that pixel: the red
, green
, blue
, and alpha
values for the color. So, with our image being 200px
wide and 200px
high, this array should have 160,000 pieces of data in it (since 200 x 200 x 4 = 160,000).
With this knowledge, we can loop over ImageData.data
in increments of 4 and grab each piece of color data to put into our own data structure. We’ll be using this newly structured data in the next step. You can reformat this part to whatever makes the most sense to you. Maybe a JSON object is easier to understand. Give it a try! :)
5. Append Some Containers
Now we’re ready to use our color data! Remember that we’ve stored them in a 2-dimensional array, so we’re going to have to do some nested looping. To continuously display the correct letter of your desired string (I used my name!), we need to keep track of how many letters we’ve already added to the page. We use the remainder (%
) operator to wrap through the string multiple times.
There’s a bunch of CSS here that makes this code look kind of gross. We could move it out into a CSS file if we don’t want to make the font-size
to work dynamically like I’ve specified. But for this demonstration, I’ve made it so you can play around with the size of the font in order to “zoom” in or out of your image. The most important attribute in our CSS is color
! We’ll set this to the RGBA
values we got in the previous step.
This is going to take a few seconds to render. There’s a TON of pixels (160,000)!
6. Resources
That’s it! Here are some links for you to read through if you have questions about some of the topics we went through. All of them go to the MDN documentation.
- Remainder (%) Operator
- The Graphics Canvas element
- CanvasRenderingContext2D
- CanvasRenderingContext2D.getImageData()
- ImageData
If you’ve made it this far, congrats!!! 🎉 I hope you found this post helpful and entertaining. If you make something cool out of this, please send me a tweet so I can see it!