Search code examples
arraysindexingprocessing

Why do i get error in processing pixelation?


I've been trying to copy a p5 script into processing for a school project but I cant completely figure it out. Here you can find the original script : https://www.youtube.com/watch?v=KfLqRuFjK5g

I keep getting this error : ArrayIndexOutOfBoundsException: Index 5832960 out of bounds for length 5801040.

Thanks in advance!

PImage img; // creates image variable

int size = 7; // element size

int startx = 0; // starting x coordinate
int starty = 0; // starting y coordinate

void preload() {
}

void setup() {
  size(500, 400); // creates canvas
  
  img = loadImage("Dubbel_augurk-01.jpg"); // preloads Virginia picture
  img.loadPixels(); // loads image
  img.resize(displayWidth, 0); // resizes image to window size
  img.updatePixels(); // updates image

}


void draw() {
  clear();
  background(0);

  int size = floor(map(mouseX, 0, width, 7, 40)); // maps mouseX value to element size

  for (var starty = 0; starty < img.height; starty++) { // creates pixel index
    for (var startx = 0; startx < img.width; startx++) {
      var index = (startx + starty * img.width) * 4;
      var r = img.pixels[index + 0];
      var g = img.pixels[index + 1];
      var b = img.pixels[index + 2];

      //var bright = ((1 * r) + (0.59 * g) + (0.11 * b)); // sets pixel value to adjusted grayscale

      fill(r,g,b); // fills element with adjusted grayscale

      rect(startx, starty, size, size);

      startx = startx + size -1; // set new startx value
    }
    starty = starty + size -1; // set new starty value
  }

}

Solution

  • There's a difference between how p5.js (html canvas) stores pixels[] and how Processing's Pimage stores pixels[].

    While they're both 1D arrays, p5.js pixels[] uses 4 values per pixels (e.g. [r1,g1,b1,a1, r2,g2,b2,a2, ...], etc.) and Processing uses 1 value per pixel (e.g. [pixel1ARGB, pixel2ARGB, etc.] for ARGB image / [pixel1RGB, pixel2RGB, etc.] for RGB images).

    This is why there's a * 4 on this line in p5.js:

    var index = (startx + starty * img.width) * 4;
    

    Hence the array index out of bounds error: the p5.js pixels[] has 4 times more elements than pixels[] in Processing.

    Remember to also change the data types (you can't use var in Processing(java)).

    Removing the unused(shadowed) startx,starty variables at the top and slightly renaming them as per Java naming conventions, your snippet would look like this:

    PImage img; // creates image variable
    
    int size = 7; // element size
    
    void setup() {
      size(500, 400); // creates canvas
      
      img = loadImage("Dubbel_augurk-01.jpg"); // preloads Virginia picture
      img.loadPixels(); // loads image
      img.resize(displayWidth, 0); // resizes image to window size
      img.updatePixels(); // updates image
    
    }
    
    
    void draw() {
      clear();
      background(0);
    
      int size = floor(map(mouseX, 0, width, 7, 40)); // maps mouseX value to element size
    
      for (int startY = 0; startY < img.height; startY++) { // creates pixel index
        for (int startX = 0; startX < img.width; startX++) {
          int index = (startX + startY * img.width);
          int pixelRGB = img.pixels[index];
    
          fill(pixelRGB); // fills element with adjusted grayscale
    
          rect(startX, startY, size, size);
    
          startX = startX + size -1; // set new startX value
        }
        startY = startY + size -1; // set new startY value
      }
    
    }
    

    (Note: this code isn't tested, but hopefully it illustrates the points on pixel indexing)

    Bare in mind, the main point of the video tutorial was on accessing/reading individual pixel values and using them in some way (e.g. mapping brightness to shape properties (circle size, line thickness, triangle colour, etc.)).

    If you simply want to display a low-res version of the image and don't care about pixel values, it might be simpler to downsample the image (resize smaller), but render at the original size (or larger) with no aliasing (to get that crisp pixel art look instead of the blurry aliasing).

    Here's a basic example you could run (remember to drag and drop the same "Dubbel_augurk-01.jpg" image on top of this sketchh too):

    PImage img; // creates image variable
    
    int downScale = 7; // how many times to scale the image down
    
    void setup() {
      size(500, 400); // creates canvas
      
      // disable aliasing
      noSmooth();
      
      img = loadImage("Dubbel_augurk-01.jpg"); // preloads Virginia picture
      img.resize(img.width / downScale, img.height / downScale); // resizes image  
    }
    
    
    void draw() {
      background(0);
    
      int size = floor(map(mouseX, 0, width, 7, 40)); // maps mouseX value to element size
    
      image(img, 0, 0, img.width * size, img.height * size);
    
    }
    

    (There are more options out there, but a bit more advanced (for example using texture(), beginShape(), vertex(x, y, u, v) and aliasing again to scale the texture coordinate or using a fragment shader (via PShader))