Warning Extreme Newbie - I want to add a batch command to an image process

Hi

I am using a copy of ADSFPixelSort by Kim Asendorf to create a video sequence. Rather than re-entering the different file names (the numbers at the end of each of the image sequence files) I’d like to just have the process applied to all files in the folder. I have read a few posts on this but can’t seem to get it right. I gather I need to use “i” as designating a variable within the filename and inserting it into the “void setup” area and change “setup” to “settings”. I have tried various copy and pastes but I am getting basic things wrong with syntax etc.
Any and all help is greatly appreciated.
The script I am using is this:
<
/********

ASDF Pixel Sort
Kim Asendorf | 2010 | kimasendorf.com

Sorting modes
0 = white
1 = black
2 = bright
3 = dark

*/

int mode = 2;

// image path is relative to sketch directory
PImage img;
String imgFileName = “Tally CU 1009”;
String fileType = “png”;

int loops = 1;

// threshold values to determine sorting start and end pixels
// using the absolute rgb value
// rgb = 255255255 = 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;
}>

Thanks!

Dom

the function settings is not needed

see settings() / Reference / Processing.org

take a look

in setup() we make an array of images using the function loadImages (see below)

then we loop over the array and treat each image individually.



// https://discourse.processing.org/t/warning-extreme-newbie-i-want-to-add-a-batch-command-to-an-image-process/40761


/*

 ASDF Pixel Sort
 Kim Asendorf | 2010 | kimasendorf.com
 
 Sorting modes
 0 = white
 1 = black
 2 = bright
 3 = dark
 
 */

int mode = 2;

// image path is relative to sketch directory
PImage[] img;
// String imgFileName = "Tally CU 1009";
String fileType = "png";

int loops = 1;

// threshold values to determine sorting start and end pixels
// using the absolute rgb value
// rgb = 255255255 = 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;

int index = 0;

// -----------------------------------------------------------------------------------------------------

void setup() {
  // use only numbers (not variables) for the size() command, Processing 3
  size(110, 110);

  // fill the array using the name of the folder INSIDE DATA folder     // img[index] = loadImage(img[index]FileName + "." + fileType);
  img = loadImages("images");

  // allow resize and update surface to image dimensions
  surface.setResizable(true);
  surface.setSize(img[0].width, img[0].height);

  // load image onto surface - scale to the available width,height for display
  image(img[0], 0, 0, width, height);
}//func

void draw() {
  //
  drawSpecial();
}//func

// -----------------------------------------------------------------------------------------------------

void drawSpecial() {

  background(0);

  if (frameCount <= loops) {

    // loop through columns
    println("Sorting Columns");
    while (column < img[index].width-1) {
      img[index].loadPixels();
      sortColumn();
      column++;
      img[index].updatePixels();
    }

    // loop through rows
    println("Sorting Rows");
    while (row < img[index].height-1) {
      img[index].loadPixels();
      sortRow();
      row++;
      img[index].updatePixels();
    }
  }//if

  // ----

  // load updated image onto surface and scale to fit the display width and height
  image(img[index], 0, 0, width, height);

  if (!saved && frameCount >= loops) {
    // save img[index]
    img[index].save("img" + "_" + mode+ frameCount + ".png");

    saved = true;
    println("Saved frame " + frameCount);

    // exiting here can interrupt file save, wait
    delay(11); // delay is nasty

    // NEXT IMAGE -------------------------------------------------------
    saved=false;
    loops=frameCount+1;
    index++;
    row = 0;
    column = 0;

    if (index>=img.length) {
      println("Last img ------------------------");
      exit();
      return;
    }

    // resize canvas and load image onto surface - scale to the available width,height for display
    surface.setSize(img[index].width, img[index].height);
    image(img[index], 0, 0, width, height);
  }//if
}//func

PImage[] loadImages(String nameFolder) {

  // called only once

  java.io.File folder = new java.io.File(dataPath("")+"/"+nameFolder);

  // get all file names
  String[] filenames = folder.list();

  // init array
  PImage[] img = new PImage[filenames.length];

  // loop over array
  for (int i = 0; i < filenames.length; i++) {
    img[i] = loadImage(dataPath("") + "/" + nameFolder + "/" + filenames[i]);
  }

  // return the new array
  return img;
}//func

void keyPressed() {
  if (saved) {
    System.exit(0);
  }
}//func

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[index].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[index].pixels[x + i + y * img[index].width];
    }

    sorted = sort(unsorted);

    for (int i = 0; i < sortingLength; i++) {
      img[index].pixels[x + i + y * img[index].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[index].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[index].pixels[x + (y+i) * img[index].width];
    }

    sorted = sort(unsorted);

    for (int i = 0; i < sortingLength; i++) {
      img[index].pixels[x + (y+i) * img[index].width] = sorted[i];
    }

    y = yEnd+1;
  }
}

// white x
int getFirstNoneWhiteX(int x, int y) {
  while (img[index].pixels[x + y * img[index].width] < whiteValue) {
    x++;
    if (x >= img[index].width) return -1;
  }
  return x;
}

int getNextWhiteX(int x, int y) {
  x++;
  while (img[index].pixels[x + y * img[index].width] > whiteValue) {
    x++;
    if (x >= img[index].width) return img[index].width-1;
  }
  return x-1;
}

// black x
int getFirstNoneBlackX(int x, int y) {
  while (img[index].pixels[x + y * img[index].width] > blackValue) {
    x++;
    if (x >= img[index].width) return -1;
  }
  return x;
}

int getNextBlackX(int x, int y) {
  x++;
  while (img[index].pixels[x + y * img[index].width] < blackValue) {
    x++;
    if (x >= img[index].width) return img[index].width-1;
  }
  return x-1;
}

// bright x
int getFirstNoneBrightX(int x, int y) {
  while (brightness(img[index].pixels[x + y * img[index].width]) < brightValue) {
    x++;
    if (x >= img[index].width) return -1;
  }
  return x;
}

int getNextBrightX(int x, int y) {
  x++;
  while (brightness(img[index].pixels[x + y * img[index].width]) > brightValue) {
    x++;
    if (x >= img[index].width) return img[index].width-1;
  }
  return x-1;
}

// dark x
int getFirstNoneDarkX(int x, int y) {
  while (brightness(img[index].pixels[x + y * img[index].width]) > darkValue) {
    x++;
    if (x >= img[index].width) return -1;
  }
  return x;
}

int getNextDarkX(int x, int y) {
  x++;
  while (brightness(img[index].pixels[x + y * img[index].width]) < darkValue) {
    x++;
    if (x >= img[index].width) return img[index].width-1;
  }
  return x-1;
}

// white y
int getFirstNoneWhiteY(int x, int y) {
  if (y < img[index].height) {
    while (img[index].pixels[x + y * img[index].width] < whiteValue) {
      y++;
      if (y >= img[index].height) return -1;
    }
  }
  return y;
}

int getNextWhiteY(int x, int y) {
  y++;
  if (y < img[index].height) {
    while (img[index].pixels[x + y * img[index].width] > whiteValue) {
      y++;
      if (y >= img[index].height) return img[index].height-1;
    }
  }
  return y-1;
}

// black y
int getFirstNoneBlackY(int x, int y) {
  if (y < img[index].height) {
    while (img[index].pixels[x + y * img[index].width] > blackValue) {
      y++;
      if (y >= img[index].height) return -1;
    }
  }
  return y;
}

int getNextBlackY(int x, int y) {
  y++;
  if (y < img[index].height) {
    while (img[index].pixels[x + y * img[index].width] < blackValue) {
      y++;
      if (y >= img[index].height) return img[index].height-1;
    }
  }
  return y-1;
}

// bright y
int getFirstNoneBrightY(int x, int y) {
  if (y < img[index].height) {
    while (brightness(img[index].pixels[x + y * img[index].width]) < brightValue) {
      y++;
      if (y >= img[index].height) return -1;
    }
  }
  return y;
}

int getNextBrightY(int x, int y) {
  y++;
  if (y < img[index].height) {
    while (brightness(img[index].pixels[x + y * img[index].width]) > brightValue) {
      y++;
      if (y >= img[index].height) return img[index].height-1;
    }
  }
  return y-1;
}

// dark y
int getFirstNoneDarkY(int x, int y) {
  if (y < img[index].height) {
    while (brightness(img[index].pixels[x + y * img[index].width]) > darkValue) {
      y++;
      if (y >= img[index].height) return -1;
    }
  }
  return y;
}

int getNextDarkY(int x, int y) {
  y++;
  if (y < img[index].height) {
    while (brightness(img[index].pixels[x + y * img[index].width]) < darkValue) {
      y++;
      if (y >= img[index].height) return img[index].height-1;
    }
  }
  return y-1;
}

1 Like

Thanks very much Chrisir. I will get on it now and give it a go.

1 Like

I am afraid I don’t really see what I am doing wrong. Just too early in the process for me I guess. can you direct me to any tutorials that might help me further? I have done the early few introductory ones, but if there is somewhere more specific about image processing I’d be very grateful. Thanks

I was just applying your code to a series of images in a folder

1 Like

I know Chrisir, and I really appreciate it, but I could even figure out how/where to put the name of my folder, sorry.

it’s pretty much at start of setup the folder images INSIDE data folder

1 Like

OK well thanks for hanging in there Chrisir.

So, I have placed all the images in a folder called Images, in a data folder within the master folder that contains the .pde file. I have replaced the original img line with your line<img = loadImages(“images”);>
I am getting message ‘The function “loadImages(String)” does not exist’

It won’t work with your Sketch.

I made a LOT of changes, because we work
with an array of images now. And we have this new function to fill the array.

Maybe just save my Sketch with a new name, copy the images into it and then run my Sketch?

Then read my sketch and understand this.

1 Like

I didn’t change the image algorithm though except for replacing image with image array

1 Like

OK thanks trying that. Do I express that the images are all titled Tally CU 1000 through to Tally CU 1591? Do I need to change that up PImage stage?

Presently it is falling over due to lack of memory. I have 16GB so I have increased processing’s allowance to 10GB but still not running. I may need to re-produce the image sequence at greater compression.

Hello @DRed,

Please format your code as a courtesy to this community:
https://discourse.processing.org/faq#format-your-code

:)

OK glv, got it. Apols.

No, as you can see in my function loadImages(), we retrieve a file list automatically. So what is in the folder is there. No need to fill in the names.

For your memory problem. Okay, at the moment we load all images at startup. That’s costly. My bad, I tested it only with 4 images…

We can also just load the images separately one after another.

  • here the function loadImage provides an image list as STRING (“imagesString”).
  • At the end of drawSpecial we load a new image img from imagesString.
  • img get processed


// https://discourse.processing.org/t/warning-extreme-newbie-i-want-to-add-a-batch-command-to-an-image-process/40761


/*

 ASDF Pixel Sort
 Kim Asendorf | 2010 | kimasendorf.com
 
 Sorting modes
 0 = white
 1 = black
 2 = bright
 3 = dark
 
 */

int mode = 2;

String[] imagesString;

// image path is relative to sketch directory
PImage img;

// String imgFileName = "Tally CU 1009";
String fileType = "png";

int loops = 1;

// threshold values to determine sorting start and end pixels
// using the absolute rgb value
// rgb = 255255255 = 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;

int index = 0;

String nameFolder="images";

// -----------------------------------------------------------------------------------------------------

void setup() {
  // use only numbers (not variables) for the size() command, Processing 3
  size(110, 110);

  // fill the array using the name of the folder INSIDE DATA folder     // img = loadImage(imgFileName + "." + fileType);
  imagesString = loadImages();

  img = loadImage(dataPath("") + "/" + nameFolder + "/" + imagesString[index]);

  // 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);
}//func

void draw() {
  //
  drawSpecial();
}//func

// -----------------------------------------------------------------------------------------------------

void drawSpecial() {

  background(0);

  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();
    }
  }//if

  // ----

  // 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("img" + "_" + mode+ frameCount + ".png");

    saved = true;
    println("Saved frame " + frameCount);

    // exiting here can interrupt file save, wait
    delay(11); // delay is nasty

    // NEXT IMAGE -------------------------------------------------------
    saved=false;
    loops=frameCount+1;
    index++;

    if (index>=imagesString.length) {
      println("Last img, exit ------------------------");
      exit();
      return;
    }

    img = loadImage(dataPath("") + "/" + nameFolder + "/" + imagesString[index]);
    row = 0;
    column = 0;

    // resize canvas and load image onto surface - scale to the available width,height for display
    surface.setSize(img.width, img.height);
    image(img, 0, 0, width, height);
  }//if
}//func

String[] loadImages() {

  // called only once

  java.io.File folder = new java.io.File(dataPath("")+"/"+nameFolder);

  // get all file names
  String[] filenames = folder.list();

  // init array
  // PImage[] img = new PImage[filenames.length];

  // loop over array
  //for (int i = 0; i < filenames.length; i++) {
  //  img[i] = loadImage(dataPath("") + "/" + nameFolder + "/" + filenames[i]);
  //}

  // return the new array
  return filenames;
}//func

void keyPressed() {
  if (saved) {
    System.exit(0);
  }
}//func

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;
}