How to modify PImage.pixels in processing.js

edited July 2017 in JavaScript Mode

I have some code that runs just fine in Processing 3. I am testing it out in processing.js, with the usual HTML wrapper.

// @pjs preload must be used to preload the image   
/* @pjs preload="graynoiz_128.png"; */

// Works in Processing. Does not work in Processing.js. Why  not?

PImage b;
String imageName = "graynoiz_128.png";
int shift;

public void setup() {
  size(128, 128);
  this.frameRate = 24;
  shift = 4;
  b = loadImage(imageName);
}

public void draw() {
  background(233, 233, 199);
  image(b, 0, 0);
  if (this.frameCount > 2) {
    b.loadPixels();
    color[] pix = b.pixels;
    rotateLeft(b.pixels, shift);
    b.updatePixels();
  }
}

/**
 * Rotates an array of ints left by d values. Uses efficient "Three Rotation" algorithm.
 * @param arr   array of ints to rotate
 * @param d     number of elements to shift
 */
public void rotateLeft(color[] arr, int d) {
  d = d % arr.length;
  reverseArray(arr, 0, d - 1);
  reverseArray(arr, d, arr.length - 1);
  reverseArray(arr, 0, arr.length - 1);
}

/**
 * Reverses an arbitrary subset of an array.
 * @param arr   array to modify
 * @param l     left bound of subset to reverse
 * @param r     right bound of subset to reverse
 */
public void reverseArray(color[] arr, int l, int r) {
  color temp;
  while (l < r) {
    temp = arr[l];
    arr[l] = arr[r];
    arr[r] = temp;
    l++;
    r--;
  }
}

The image loads just fine in FireFox (using MAMP). It shifts/animates fine in Processing, but not in the web page.

I want to do more complex things with the image pixels, but there seems to be some kind of error I need to resolve first, though nothing shows in the console.

Thanks,

-- Paul

Tagged:

Answers

  • Have you consider switching to p5.js? It is very similar to processing but with the main difference of using javascript. From my limited experience, you get more for your buck going p5.js vs using p.js.

    Did you check also the console log provide by the browser? Also, can you provide your image? Does it need to be square?

    Kf

  • Make sure "graynoiz_128.png" is the the root directory of your webpage.
    Otherwise it may get tainted. And then you won't be able to access its pixels[]. :-SS

    Also consider hosting it in https://OpenProcessing.org/sketch/create
    Select Mode Processing.js. You can upload your picture there at Files tab too! $-)

  • I can provide the image. It is in the root directory of the page. There are no errors in the console. I guess I can step through the debugger to see what happens with the data. For what I want to do once I resolve this problem, a square image with dimensions that are a power of 2 is needed. I've been checking out p5.js, which I haven't worked with before, but it seems promising.

    http://paulhertz.net/wrong2017/imagescan03/imagescan03.html

    thanks,

    -- Paul

  • edited July 2017

    Okay, here's a solution. I copy the loaded PImage to a new PImage and I copy the new PImage's pixel array, modify it, and copy it back. Clunky.

    I peered under the hood at the way processing.js handles the pixels[] array to guess at the need to copy the array back and forth. Processing.js should post an error about copying attempts to modify the pixels of a "remotely loaded PImage." That would be a PImage loaded from a URL, not the case here--but it misbehaves anyhow, without an error message.

    // @pjs preload must be used to preload the image
    
    /* @pjs preload="graynoiz_128.png"; */
    
    // Works in Processing. Does not work in Processing.js. Why  not?
    // 
    
    PImage b;
    String imageName = "graynoiz_128.png";
    int shift;
    color[] pix;
    
    
    public void setup() {
      size(128, 128);
      this.frameRate = 24;
      shift = 4;
      // it seems to be necessary to copy the loaded PImage to a new PImage
      PImage p = loadImage(imageName);
      b = new PImage(p.width, p.height);
      b.loadPixels();
      for (int i = 0; i < b.pixels.length; i++) {
        b.pixels[i] = p.pixels[i];
      }
      b.updatePixels();
      pix = new color[b.pixels.length];
      println("----- imagescan03 -- Web version -----");
    }
    
    
    public void draw() {
      background(233, 233, 199);
      image(b, 0, 0);
      // it also seems to be necessary to copy the pixel array, modify it, and copy it back
      if (this.frameCount > 2) {
        b.loadPixels();
        for (int i = 0; i < b.pixels.length; i++) {
          pix[i] = b.pixels[i];
        }
        rotateLeft(pix, shift);
        for (int i = 0; i < b.pixels.length; i++) {
          b.pixels[i] = pix[i];
        }
        // rotateLeft(b.pixels, shift);
        b.updatePixels();
      }
    }
    
    
    
    /**
     * Rotates an array of ints left by d values. Uses efficient "Three Rotation" algorithm.
     * @param arr   array of ints to rotate
     * @param d     number of elements to shift
     */
    public void rotateLeft(color[] arr, int d) {
      d = d % arr.length;
      reverseArray(arr, 0, d - 1);
      reverseArray(arr, d, arr.length - 1);
      reverseArray(arr, 0, arr.length - 1);
    }
    
    
    /**
     * Reverses an arbitrary subset of an array.
     * @param arr   array to modify
     * @param l     left bound of subset to reverse
     * @param r     right bound of subset to reverse
     */
    public void reverseArray(color[] arr, int l, int r) {
      color temp;
      while (l < r) {
        temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
        l++;
        r--;
      }
    }
    

    onwards,

    -- Paul

  • modify it, and copy it back

    Interesting. If loaded PImages are treated differently, then perhaps as a workaround you could:

    1. load a PImage from file/url/whatever
    2. copy it, only once, to a new PImage
    3. only use the new one. modify at will. never copy back.

    Not tested, just an idea.

  • Yes, I thought of doing that. The copy also misbehaved until I broke its pixels[] out into a copy. Both fixes seem to be necessary.

    thanks,

    -- Paul

  • Thxs for sharing your solution! I wonder how much support is there for P.js nowadays...

    Kf

  • edited July 2017

    I started out using P.js some years ago, but it looks like there hasn't been an update since 2014. It was a really ingenious tool, started by John Resig of jQuery fame, but p5.js is now where most of the development activity seems to be. There's an IRC channel for developers, but I haven't joined to find out how active it is.

    In performance terms, it makes more sense to work with JavaScript directly and access its unique features, so I think I will make the transition. Most of my current work though is in Java, using the Processing library, in Eclipse.

    -- Paul

Sign In or Register to comment.