I’d like to be able to grab a small area from the canvas and process the pixels in such a way that I can alter the color of intersecting lines. Here’s an example of what I’m trying to accomplish.
void setup(){
size(200, 200); // P3D fixes PImage alpha?
background(255, 255);
noFill();
stroke(0, 100);
strokeWeight(1);
strokeCap(SQUARE);
rect(59, 59, 82, 82);
strokeWeight(20);
line(100, 60, 100, 140);
line(60, 100, 140, 100);
// is there a way to grab only a rectangle from the canvas instead of the whole thing?
loadPixels();
PImage img = createImage(80, 80, RGB);
int cnt = 0;
for (int x=60; x<140; x++){
for (int y=60; y<140; y++){
int loc = x + y*width;
img.pixels[cnt] = pixels[loc];
float r = red(img.pixels[cnt]);
float a = alpha(img.pixels[cnt]);
if (cnt % 250 == 0){ println(cnt," ",r," ",a); }
if (r == 155){
img.pixels[cnt] = color(0);
// however, using the P3D renderer, img.pixels[cnt] = color(0, 20) doesn't seem to have alpha... WTF?
} else if (r < 155) {
img.pixels[cnt] = color(255);
} else {
// where's the alpha?
// (fixed using P3D renderer, which seems to initialize a PImage object with color(0,0))
img.pixels[cnt] = color(255, 0);
// however, using the P3D renderer, img.pixels[cnt] = color(0, 0, 255, 0); doesn't seem to have alpha... WTF?
}
cnt++;
}
}
image(img, 0, 0);
}
I have a few questions, since I find this approach a bit awkward, and it doesn’t entirely work. I figure there’s got to be a better way to do this.
Is there a way to grab only a part of the canvas rather than execute loadPixels() which grabs it all?
PImage provides a way to get() pixel colors, or to grab a rect of pixels. But loadPixels() only seems to be able to access its color data via the pixels array. Is there a way to use get() from loadPixels()?
Printing the red and alpha values shows that loadPixels() doesn't retrieve alpha. The doc for PImage.copy() says: "No alpha information is used in the process, however if the source image has an alpha channel set, it will be copied as well.", which implies that the canvas doesn't contain alpha. So how do I obtain alpha information from the canvas?
The PImage object I create replaces white with full transparency, yet it doesn't work. Why not? Because the source image doesn't have alpha? But since I'm defining the pixels in the object, shouldn't it be able to create its own alpha? Actually, I answered my own question by trying the P3D renderer, which seems to initialize a PImage object with color(0,0). And yet, when I apply alpha to a pixel, it seems to ignore it. What's going on?
Ok, so I’m using PGraphics to create my image now so that I’ll have alpha. According to the docs “Unlike the main drawing surface which is completely opaque, surfaces created with createGraphics() can have transparency. This makes it possible to draw into a graphics and maintain the alpha channel. By using save() to write a PNG or TGA file, the transparency of the graphics object will be honored.” Great, just what I want.
But… if I set the my PGraphics object to use the P3D renderer I get a NullPointerException in my pixel loop. If I don’t set the P3D renderer I don’t get alpha from my PGraphics object.
Is there some other obvious thing I’m overlooking here?
void setup(){
size(200, 200, P3D);
background(255);
noFill();
stroke(0, 100);
strokeWeight(1);
strokeCap(SQUARE);
rect(59, 59, 82, 82);
//// if I set the renderer to P3D...
//PGraphics pg = createGraphics(80, 80);
PGraphics pg = createGraphics(80, 80, P3D); // P3D restored
pg.beginDraw();
pg.background(255);
pg.stroke(0, 100);
pg.strokeWeight(20);
pg.strokeCap(SQUARE);
pg.line(40, 0, 40, 80);
pg.line(0, 40, 80, 40);
pg.endDraw();
imageMode(CENTER);
image(pg, 100, 100);
pg.loadPixels(); // thx TfGuy44 post 11 below!
for (int x=0; x<pg.width; x++){
for (int y=0; y<pg.height; y++){
int loc = x + y*pg.width;
// ... I used to get a NullPointerException here, but not anymore with pg.loadPixels()
float r = red(pg.pixels[loc]);
// ... but the P3D renderer (still) gives me no alpha
float a = alpha(pg.pixels[loc]);
if (loc % 250 == 0){ println(loc," ",r," ",a); }
}
}
}