Main Page » Programming Projects »



Always use secure-HTTP / Unsecure HTTP / Permanent Link

A simple program I made for the purpose of shifting all the bits in an image, for the purpose of creating a comic (as-yet-unreleased) for Square Root of Minus Garfield.


System Requirements

ImgBitShift requires .Net Framework 4.0, and Windows 7, Windows Vista SP1 or later, or Windows XP SP3. It will probably function on Macintosh/Linux using the Mono framework; MoMA showed no problems.

How It Works

Computers store datas in "bits" (binary digits), which may have a value of 1 or 0; binary numbers are counted up in the form of 1 = 0001, 2 = 0010, 3 = 0011, 4 = 0100, 5 = 0101, and so on. In a computer, bits are organized in groups of eight called bytes, which can have any value between zero (00000000) and 255 (11111111), for a total of 256 possibilities.

With a few ifs and buts, a single pixel in an image is represented with three bytes: one for red, one for green, and one for blue; hence, "RGB." (They may be stored in an image file in an entirely different way, but once the color gets to your screen, that's basically how it works.) Bright red is "255, 0, 0", dark purple is "128, 0, 128", cyan would be "0, 255, 255," and so on. Now, I won't try to make any general statements, but C# allows you to load an image in your computer's memory with the bytes for every single pixel in order (with the size of the image stored separately). A 600x175 image of a Garfield comic, for instance, would have 105000 pixels, for a total of 315000 bytes all in a row. Nothing differentiates the individual bytes from each other except their location in memory.

Bit-shifting is simple: you take all the bits in a byte or group of bytes, and shift them to the left or right. Take a byte with the value of 00110101, shift it two bits to the left, and you get 11010100! Take two bytes with a combined value of 1100100101011000, shift them three bits to the right, and you get 0001100100101011. ImgBitShift applies this process to an entire image, apart from its width and height.1 Because each pixel uses three bytes, I set it up so that you can shift by up to 23 bits either left or right.

Notice how, with just about every image that isn't just a white or black square, that this often results in wildly different colors. Even sifting it one bit to the left, a shade of pink might turn red, and a darker shade of pink might turn cyan! Well, this is how bit-shifting works:

Let's say you had a pixel with the color values "252, 134, 148", or 11111100 10000110 10010100 in binary. When we shift it one bit to the left, it becomes 11111001 00001101 00101001 (with I guess that final 1 coming from the next pixel). These values translate to "249, 13, 41"! See what happened? The green and blue values began with 1s followed by multiple 0s, so when the byte got shifted by one pixel, that leading "1" got lopped off, leaving behind the trail of zeroes. The red, however, started with a whole row of 1s, so that it was still a fairly high value after the shift.

Now let's look at a pixel which starts out as "190, 102, 108", or 10111110 01100110 01101100. Shift it one bit to the left, and you get 01111100 11001100 11011001, or "124, 204, 217" — due to the arrangement of the bits, the blue and green values are now higher than the red value!

The reason it gets wilder the further to the left you shift it (or, starting from the right, it starts out completely wild and then gets less-so) is because after the highest few bits or so, you're a lot less likely to notice the difference. I mean, can you even see the diference between "255, 153, 153" and "254, 151, 151" (as opposed to "239, 121, 121"? For this reason, the rightmost bits (the "least significant digits") of the values in an image are "allowed" to be more variable than the most significant digits. However, when you move the least-significant digits into positions of greater significance, the variability becomes obvious.

1It should be noted that, while a standard bit-shifting operation simply discards the extraneous bits and replaces them with zeroes, i.e. 10101111 shifted left two bits would become 10111100, ImgBitShift simply wraps them around, so that every byte in the sequence takes the bits from the next/previous byte (and the first byte takes bits from the last byte or vice-versa).

3 Comments (auto-closed) (rss feed)

Formica Archonis

A novel little idea. Really makes JPG artifacts obvious the further away from an 8-bit boundary it gets. And makes some well-shaded art look like something that should be next to a blacklight poster.

(I've submitted a few strips to that comic, but they were more photoshoppy ones and less programmatic ones.)


I notice using this program with any image complex enough to use shading, it tends to make the image look rather glitchy unless you shift by a multiple of 8 (a full byte in other words). I guess it makes sense thinking about it but it's a bit interesting nonetheless.

Dizzy H. Muffin

I kind of glossed over both of those things, but yeah, you're right.