top of page

Lab: Pixel Sorting

Writer's picture: Corrina Crazie EspinosaCorrina Crazie Espinosa

Updated: Jan 22


Pixel sorting is a coded algorithm that sorts pixels in the rows/columns of images, depending on a variety of factors including color, brightness, etc., to create an interesting glitch effect. It was popularized (possibly invented) by artist Kim Asendorf. There are multiple ways to approach this type of glitch, I will show you how to use the code to make pixel sorted glitches, and also how to fake pixel sorted glitches in Photoshop.


Directions:

For this Lab you will need to download free open source software called Processing: https://processing.org/download/

You will also need to download the processing script called ASDFPixelSort, available on GitHub: https://github.com/kimasendorf/ASDFPixelSort


Step 1: Download processing, and the processing script. Extract all the files.


Step 2: Double click the processing script to open it in processing, you should see the code.


Step 3: In the same folder where your script is located, put 4 image files that you would like to glitch. Make sure that your files are not too large. I recommend making them no longer than 6 inches in any direction.


Step 4: In the code, locate where it says "String imgFileName = "MyImage"" and replace the word "MyImage" with the name of the first image file you want to glitch.


Step 5. In the code, locate where it says "int mode = 1;" and choose which mode you will try first, 0 = black, 1 = brightness, or 2 = white. Change the number in the code to the number of mode you choose.


Step 6. In the code, locate where it says:

"int blackValue = -16000000;

int brightnessValue = 60;

int whiteValue = -13000000;"

make adjustments to the numbers for the area that coincides with the mode you are using. mode 0 is blackValue, mode 1 is brightnessValue, and mode 2 is whiteValue.


Step 7. Hit the Green triangle "play" or "run button at the top of your screen to generate the glitch. Try out each mode for each image. Adjust the numbers for each mode until the desired effect is achieved.


You must have 16 final images for your blog, the original 4 images, and 3 glitched images for each original (1 for each mode). Your blog post should look something like this:








CODE:


/********


ASDF Pixel Sort

Kim Asendorf | 2010 | kimasendorf.com

Sorting modes

0 = white

1 = black

2 = bright

3 = dark

*/


int mode = 0;


// image path is relative to sketch directory

PImage img;

String imgFileName = "mountains";

String fileType = "jpg";


int loops = 1;


// threshold values to determine sorting start and end pixels

// using the absolute rgb value

// r*g*b = 255*255*255 = 16581375

// 0 = white

// -16581375 = black

// sort all pixels whiter than the threshold

int whiteValue = -12345678;

// sort all pixels blacker than the threshold

int blackValue = -3456789;

// using the brightness value

// sort all pixels brighter than the threshold

int brightValue = 127;

// sort all pixels darker than the threshold

int darkValue = 223;



int row = 0;

int column = 0;


boolean saved = false;


void setup() {

img = loadImage(imgFileName + "." + fileType);

// use only numbers (not variables) for the size() command, Processing 3

size(1, 1);

// allow resize and update surface to image dimensions

surface.setResizable(true);

surface.setSize(img.width, img.height);

// load image onto surface - scale to the available width,height for display

image(img, 0, 0, width, height);

}



void draw() {

if (frameCount <= loops) {

// loop through columns

println("Sorting Columns");

while (column < img.width-1) {

img.loadPixels();

sortColumn();

column++;

img.updatePixels();

}

// loop through rows

println("Sorting Rows");

while (row < img.height-1) {

img.loadPixels();

sortRow();

row++;

img.updatePixels();

}

}

// load updated image onto surface and scale to fit the display width and height

image(img, 0, 0, width, height);

if (!saved && frameCount >= loops) {

// save img

img.save(imgFileName + "_" + mode + ".png");

saved = true;

println("Saved frame " + frameCount);

// exiting here can interrupt file save, wait for user to trigger exit

println("Click or press any key to exit...");

}

}


void keyPressed() {

if (saved) {

System.exit(0);

}

}


void mouseClicked() {

if (saved) {

System.exit(0);

}

}


void sortRow() {

// current row

int y = row;

// where to start sorting

int x = 0;

// where to stop sorting

int xEnd = 0;

while (xEnd < img.width-1) {

switch (mode) {

case 0:

x = getFirstNoneWhiteX(x, y);

xEnd = getNextWhiteX(x, y);

break;

case 1:

x = getFirstNoneBlackX(x, y);

xEnd = getNextBlackX(x, y);

break;

case 2:

x = getFirstNoneBrightX(x, y);

xEnd = getNextBrightX(x, y);

break;

case 3:

x = getFirstNoneDarkX(x, y);

xEnd = getNextDarkX(x, y);

break;

default:

break;

}

if (x < 0) break;

int sortingLength = xEnd-x;

color[] unsorted = new color[sortingLength];

color[] sorted = new color[sortingLength];

for (int i = 0; i < sortingLength; i++) {

unsorted[i] = img.pixels[x + i + y * img.width];

}

sorted = sort(unsorted);

for (int i = 0; i < sortingLength; i++) {

img.pixels[x + i + y * img.width] = sorted[i];

}

x = xEnd+1;

}

}



void sortColumn() {

// current column

int x = column;

// where to start sorting

int y = 0;

// where to stop sorting

int yEnd = 0;

while (yEnd < img.height-1) {

switch (mode) {

case 0:

y = getFirstNoneWhiteY(x, y);

yEnd = getNextWhiteY(x, y);

break;

case 1:

y = getFirstNoneBlackY(x, y);

yEnd = getNextBlackY(x, y);

break;

case 2:

y = getFirstNoneBrightY(x, y);

yEnd = getNextBrightY(x, y);

break;

case 3:

y = getFirstNoneDarkY(x, y);

yEnd = getNextDarkY(x, y);

break;

default:

break;

}

if (y < 0) break;

int sortingLength = yEnd-y;

color[] unsorted = new color[sortingLength];

color[] sorted = new color[sortingLength];

for (int i = 0; i < sortingLength; i++) {

unsorted[i] = img.pixels[x + (y+i) * img.width];

}

sorted = sort(unsorted);

for (int i = 0; i < sortingLength; i++) {

img.pixels[x + (y+i) * img.width] = sorted[i];

}

y = yEnd+1;

}

}



// white x

int getFirstNoneWhiteX(int x, int y) {

while (img.pixels[x + y * img.width] < whiteValue) {

x++;

if (x >= img.width) return -1;

}

return x;

}


int getNextWhiteX(int x, int y) {

x++;

while (img.pixels[x + y * img.width] > whiteValue) {

x++;

if (x >= img.width) return img.width-1;

}

return x-1;

}


// black x

int getFirstNoneBlackX(int x, int y) {

while (img.pixels[x + y * img.width] > blackValue) {

x++;

if (x >= img.width) return -1;

}

return x;

}


int getNextBlackX(int x, int y) {

x++;

while (img.pixels[x + y * img.width] < blackValue) {

x++;

if (x >= img.width) return img.width-1;

}

return x-1;

}


// bright x

int getFirstNoneBrightX(int x, int y) {

while (brightness(img.pixels[x + y * img.width]) < brightValue) {

x++;

if (x >= img.width) return -1;

}

return x;

}


int getNextBrightX(int x, int y) {

x++;

while (brightness(img.pixels[x + y * img.width]) > brightValue) {

x++;

if (x >= img.width) return img.width-1;

}

return x-1;

}


// dark x

int getFirstNoneDarkX(int x, int y) {

while (brightness(img.pixels[x + y * img.width]) > darkValue) {

x++;

if (x >= img.width) return -1;

}

return x;

}


int getNextDarkX(int x, int y) {

x++;

while (brightness(img.pixels[x + y * img.width]) < darkValue) {

x++;

if (x >= img.width) return img.width-1;

}

return x-1;

}


// white y

int getFirstNoneWhiteY(int x, int y) {

if (y < img.height) {

while (img.pixels[x + y * img.width] < whiteValue) {

y++;

if (y >= img.height) return -1;

}

}

return y;

}


int getNextWhiteY(int x, int y) {

y++;

if (y < img.height) {

while (img.pixels[x + y * img.width] > whiteValue) {

y++;

if (y >= img.height) return img.height-1;

}

}

return y-1;

}



// black y

int getFirstNoneBlackY(int x, int y) {

if (y < img.height) {

while (img.pixels[x + y * img.width] > blackValue) {

y++;

if (y >= img.height) return -1;

}

}

return y;

}


int getNextBlackY(int x, int y) {

y++;

if (y < img.height) {

while (img.pixels[x + y * img.width] < blackValue) {

y++;

if (y >= img.height) return img.height-1;

}

}

return y-1;

}


// bright y

int getFirstNoneBrightY(int x, int y) {

if (y < img.height) {

while (brightness(img.pixels[x + y * img.width]) < brightValue) {

y++;

if (y >= img.height) return -1;

}

}

return y;

}


int getNextBrightY(int x, int y) {

y++;

if (y < img.height) {

while (brightness(img.pixels[x + y * img.width]) > brightValue) {

y++;

if (y >= img.height) return img.height-1;

}

}

return y-1;

}


// dark y

int getFirstNoneDarkY(int x, int y) {

if (y < img.height) {

while (brightness(img.pixels[x + y * img.width]) > darkValue) {

y++;

if (y >= img.height) return -1;

}

}

return y;

}


int getNextDarkY(int x, int y) {

y++;

if (y < img.height) {

while (brightness(img.pixels[x + y * img.width]) < darkValue) {

y++;

if (y >= img.height) return img.height-1;

}

}

return y-1;

}

 
 

Comments


A tremendous amount of soup was harmed in the making of this website.

Autonomous Soup New Media Art © 2016

bottom of page