🏓pong🏓 - fully playable, hidden inside a 24px by 24px image 😎 [hiding text and code in images]
4 min read
Sometimes you just have to set yourself silly challenges to help you learn. And this is one of those.
I wanted to see how tiny I could make an image and hide an entire game inside it!
So I set about writing my own (very rudimentary) steganography library.
If you aren't familiar with steganography it is the practice of hiding text, images or audio within an image or video.
This is normally done with clever bit flipping - but I am too smol brained for that!
Instead I realised I could use the alpha channel to encrypt data.
As the alpha channel on an image (the transparency) has 255 options that gives lots of ways to encrypt the data.
In the fiddle below there are 3 stages for encryption and a fourth for decryption.
Step 1 - grab the image we want to encode our data into
In the first step we simply load an image in.
I have already included the InHu logo (which is large enough to contain the whole of jQuery!) but you can choose your own image if you want.
You can also change the text you want encrypting by entering it in the textarea (by default it is a code-golfed version of pong!)
Step 2 - resize the image as small as possible.
In the second step you choose the "depth" we can encode.
This is essentially how visible the transparency is (how much information we store per pixel).
More simply it is a strange implementation of converting numbers to a given Base. So 2 is essentially binary (but using 1 and 2 for the bits) and 16 is essentially hexadecimal but using numbers 1-16 instead of numbers and letters.
A low number (e.g. 2) will require a larger image to encrypt the data but the transparency will be much lower.
A high number (e.g. 16) will require a smaller image but you may see the transparency,
So high numbers for smaller images but more likelihood of being noticed.
I recommend setting this to "8" as it is not noticeable on most images but still results in small image outputs.
There is also a checkbox for using the full ASCII table if you want to use special characters. I would leave this unchecked at first.
Once you have entered your preferences click "Calculate the smallest image size we can use".
This will then resize the original image to the minimum size possible to contain the information.
Step 3 - encode the data
Click the "Encode" button to generate the final image.
Here you can see if there are any visible differences between the two images. If there are then you can go back a step and lower the number a bit.
Step 4 - decode the image
If you click "Decode" you should see a fully playable version of pong appear below (assuming you haven't changed the text in the textarea! If you have then you should see your text repeated below)
Controls are Q and A for player 1 and P and L for player 2. Have fun!
Want to see the whole of paradise lost in an image?
I will warn you - the processing on this takes quite a while! You might not want to do this if you are on a mobile!
View the whole of paradise lost as part of a JS fiddle here (It takes a while to load so I didn't include it inline in the article)
A fun experiment indeed - there are loads of things we could do better - character maps instead of adding each character would reduce large files size significantly. Ironically though it made pong larger!
Obviously for those of you who know about steganography, this is normally done with bit flipping, but I though the opacity channel was an interesting alternative as instead of a max of 3 bits per pixel (red, green and blue) we get up to 255 bits of information per channel (obviously we can't use all 255 and maintain a reasonable image), but I decided 16 bits was the max!
It was fun trying to work out how to have a flexible base for encoding (it works for base2,3,4,5,6....14,15,16...etc.), there are probably much better ways to do it though!
Anyway, I hope you enjoyed this silly post!
p.s. the original Pong code was taken from this stack overflow answer