Ascii Stereogram Maker

I heart fishI heart fishI heart fishI heart fishI heart fishI heart fi
==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_
I heart fishI heart fishI heart fishI heart fishI heart fishI heart fi
==):^{} (_()==)1^{} (_()==)1^{} (_()==)1^{} (_()==)1^{} (_()==)1^{} (_
I heart fishI hart %fishI har %fishI har %fUishI har %fUishI har %fUis
==):^{} (_()==):^} (_F()==)^} (_F()==)^} (_F(D)==)^} (_F(D)==)^} (_F(D
I heart fishI heat fishI heat fishI heagt fshI bheagt fshI bheagt fshI
==):^{} (_()==):^{}(_()==):^{}(_()==):^a{}(()==):E^a{}(()==):E^a{}(()=
I heart fishI heart fshI heart fshI heart fshI hear+t fshI hear+t fshI
==):^{} (_()==):^{} (()==):^{} (()==):^{} (()==):^{U} (()==):^{U} (()=
I heart fishI heartfishI heartfishI heartofisI he+artofisI he+artofisI
==):^{} (_()==):^} (_()==):^} (_()==):^} $(_()==):^} $(_()==):^} $(_()
I heart fishI heat fi3shI hat fi3shI hat fi3shI h9at fi3shI h9at fi3sh
==):^{} (_()==)^{} J(_()==)^{} (_()==)^{} (_()=r=)^{} (_()=r=)^{} (_()
I heart fishI hdart fishI hdart fishI hdart fishI hdart fishI hdart fi
==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_
I heart fishI heart fishI heart fishI heart fishI heart fishI heart fi
==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_
I heart fishI heart fishI heart fishI heart fishI heart fishI heart fi
==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_()==):^{} (_

This stereogram was made with the Ascii Stereogram Maker at ptocheia.net


I’d found an ascii stereogram maker on the web a little while back, and I’d really wanted to try replicating it. I’d already been playing around in Photoshop with imaged based stereograms, just to get the concept down, and that worked more or less ok. For flat images with depth levels occuring in steps, mind you, I’m still not sure of how to create gradiated depth like you see in Magic Eye pictures. I know there’s programs out there that’ll do it, but I have no idea how to replicate that manually.

First, I needed a giant block of repeating ascii characters. Easy enough, the user inputs 1 to 4 strings of characters from which the program generates the giant ascii character block. Only from 9 to 15 characters is allowed per string, as that seems to me to be the min and max boundaries for the distance one’s eyes feel comfortable crossing. So once this block is created, I copied and pasted chunks into my text editor (go Vim!) to figure out how to make this work. With images, you essentially chop out the shape you want and move it over a few spaces. This is done with ascii by adding and removing characters. In a string of 1234567890, you could remove the 2, leaving 134567890, to have the shape start there. To end the shape, you add a completely new character. So, to end your tiny shape a few characters later, you might do 134567S890. One important thing: when the 2 is removed, it is removed permanently, and when the S is added, it is also added permanently. So a longer string, with this shape in the middle, would look like 1234567890134567S90134567S890. Or, to make a more visual example, it would look like this:


12345678901234567890123456789012345678901234567890
12345678901234567890134567S890134567S890134567S890
12345678901234567890134567S890134567S890134567S890
12345678901234567890134567S890134567S890134567S890
12345678901234567890123456789012345678901234567890

You should be able to see a small box floating in the center. When you blur your eyes together, the majority of the numbers should overlap and still appear as that number. The floating box starts at the point where the 2 is first removed. When your eyes are blurred, there will be a 3 that overlaps the previous 2, due to the 2’s removal. The 2 characters not aligning together creates a visual dissonance, which causes the subsequent characters to jump out (or jump in, depending on how you’re looking at the depth illusion). This new pattern, with the 2 gone, will repeat until the shape ends, when the S gets added. The S tries overlapping with the 7, creating more visual dissonance, ending the shape. This also reverts the string of numbers to it’s original length, allowing them to match up with the other non-repeating rows. Leaving the end character out still leaves the illusion of depth, it just continues until the end of the chunk of characters, like this:


12345678901234567890123456789012345678901234567890
12345678901234567890134567890134567890134567890123
12345678901234567890134567890134567890134567890123
12345678901234567890134567890134567890134567890123
12345678901234567890123456789012345678901234567890

You can move around the start and end characters for each line of text to create more interesting shapes. A shape can also start and stop multiple times on the same line. If you have the sort of eyes that can take it, you can make a shape by blurring your eyes and manually changing the characters in your text editor. This will cause headaches after not too long, though!


123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345689012345689W012345689W012345689W01
12345678901234567890123467801234678A012#34678A012#34678A012#
12345678901234567890124567890124567890124X567890124X56789012
123456789012345678901234567890123456789012345678901234567890

The next problem was figuring out how to do this from a shape created from checkboxes. All of the checkboxes are named ‘boxes[]’ and each of their values is based on it’s location in the grid. I.E., if the checkbox valued ‘6_13’ is checked, then that means the 13th character in the 6th row will be part of a shape.

A really long string is produced for each character string that it submitted. It’s extra long to accommodate for the fact that it might get shortened a bit, depending on how many shapes get added per row and the length of that shape. These strings get used in order, this order repeating until all of the rows have been created. For this program, I used 20 rows. A new instance of each string is used for new rows, so that changes made to the last instance of that string aren’t carried over.

The key to translating the checkboxes to a stereogram is the fact that I only need to pay attention to the starting points and ending points of a shape for each row. To check for when a shape starts, I just look to see if the current box is checked and, if so, if the box previous to the current is unchecked. If so, a character gets removed at that point, as well as for the rest of the instance of that long string. To check for when a shape ends, I look to see if the current box is checked, and if so, check if the following box is unchecked. If this is the case, a new character gets inserted at the point in the string where the following box would be located. This must happen for the location of the next box, as the current box marks the last position of the current shape. This also prevents a problematic situation from arising when only one box is checked, as, when the pointer is on the location of that one box, it would represent both the start and the end of that shape. There needs to be some set of character(s) in the string between when a character is removed and when a new character is inserted, else that small shape won’t exist on the stereogram.

It’s also important to keep any preexisting characters in a string from being used as the inserted character at the end of a shape. If there are too many duplicate characters, it becomes harder on the eyes to distinguish patterns, which can break a more complex ascii stereogram.

I should mention that it took me a bit of time to come to the solution that I did. My first attempt involved just storing the original 9-15 character strings in multidimensional arrays (i.e. $mywords[word][letter]) and doing a lot of looping. This got complicated when I had to figure out what to do if I needed to remove a character but was at the end of the array, etc. as well as length issues. The inane logic eventually forced my brain to think of the much easier solution of chucking the multidimensional array for the much simpler $mywords[word], and just dealing with strings.

I made a stripped down version of the code, if anyone feels like seeing how I did it or trying to implement other things with it. Here’s the input and output page, zipped (or ‘rarred’, rather). I left out anything having to do with color in the stripped-down version, as that’s just window dressing. The widget I used for selecting color is located here, if anyone is interested. I had given thought to assigning a separate color to each character, just to see how it would look. but never got around to actually trying that.

Leave a Reply