Here’s a short list of some of the functions I’ve implemented.
- Random dithering rates each pixel against a random value, if it’s higher than that value it’s a white pixel, if it’s lower it’s black. I’ve also colorized it by rating each channel value of the pixel.
- Color shifting will play with the values by boosting or re-arranging the red, green, or blue channels.
- Slices move chunks of pixel and channel values in interesting ways, sometimes shifting colors as well.
- Sorts Sort chunks of pixels in place, producing gradient-like stripes of colors within the image.
- Fractals Create fractal-like ghosts and shadows by repeating an image on itself
This is a work in progress, so all of the code is subject to change; also I’m working on updating this to work with node.js on a separate branch*, so all the code will have to be adjusted for that anyhow.
There are 4 different interfaces here, each offering their own unique take on the task,
- Demo will run each function against the original image once
- Glitch Only will apply a random set of glitches to the original image several times
- Glitch Cruiser When you upload an image it appears in the center surrounded by 8 glitchy alternatives. If one of these images suits your fancy, click on it and it will become the new source for the next round of glitches. If you do not like any of the suggested glitches, click on the center image, and you’ll get the next 8 glitch options, but your source will not be changed.
- Glitch Chooser this allows you to select functions from a drop-down list to apply to an image, you can either apply a tranformation, or reset it to the way it was before, you can even reset it to the original image. Unliked Glitch Cruiser, you won’t be able to see the results of a function before selecting it, but you can replace the latest image transformation again and again until you can see your desired results.
imageData.data is a
This array holds all the data for every pixel in the image, however it’s stores 8-bit values, channel-by-channel instead of pixel-by-pixel, that is to say
Uint8ClampedArray stores the image data like
This means that to deal with this array, you’re going to have to increment the loop by 4, and handle the channel-values each time like this function that inverts a pixel’s color:
This is a slow & tedious task, but there are other typed arrays, like
Uint32Array which stores 32-bit values, converting an 8-bit array to a 32-bit array would cut the size of the array by a quarter.
So as a Uint32Array color data is stored like
[ARGB, ARGB, ARGB, ARGB..., inverting is now just one operation.
Here, a bitwise NOT (
~) inverts the bits, and OR
| applies a mask to keep the alpha channel at 100%.
You may also notice that I’m using the
imageData.data.buffer to make a 32-bit view of the 8-bit data, this means that you don’t have to set the data back into the array, because it passes through to the original variable naturally.
While all the above is true for most personal computers which store data in Little Endian, some other machines may use Big Endian notations, which would reverse the order of the data from RGBA to ABGR. If you were making imaging software you’d probably want to account for that, but since the point of this project is to maim images it’s only mildly important to ensure the alpha channel is applied correctly (or just set to 100%.)
* now that I’m planning to make this into a node-based tool, and eventually distribute it on NPM, I’m thinking I’d be better off making this an extension of camanjs because they’ve already got so much figured out. Also I think by that point a name change might be in order.