We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › PImage.copy method giving me some flak
Page Index Toggle Pages: 1
PImage.copy method giving me some flak (Read 1006 times)
PImage.copy method giving me some flak
Feb 20th, 2009, 9:57pm
 
Hi, new here. If anyone can spare some time for someone new to Processing, it'd be really appreciated.

You'll forgive me if the answer here is obvious. My Java experience is fairly limited, so I don't really know my way around as well as I'd like to. But, anyway, I've been running into a bit of a problem and I couldn't find what I was looking for in the language reference.

Basically, I'm writing a simple game. I've put together a png of the tileset I'm using, and loaded it into a PImage object. The loadTiles method is supposed to split it into an array of square PGraphics objects, so I used the PGraphics.copy method. Trouble I ran into was that it was resulting in blurring, as if it was resizing the images. This didn't make much sense, since both the source and destination dimensions were the same. It wasn't until I'd been messing around with it for about an hour that I figured out copy seems like it won't touch the pixels at the very bottom and far right, which I assumed was a safeguard against trying to pull pixels from out-of-bounds. By shrinking the height of the destination by 1, I got an unstretched image (save for the far right tile), but lost my bottom row of pixels. Now, I figure I could add a pad of empty pixels around the tiles, but if I could just get the copy method to grab the pixels I want it to it would be a bit simpler.

I included the code too.

void loadTiles(String tilesToLoad) {
 PImage tileset = loadImage(tilesToLoad);
 int numTiles = (int) tileset.width/tileset.height; //typecasts in case the tileset's been messed with
 tileSize = tileset.height;
 tiles = new PGraphics[numTiles];
 //tiles was already declared as a class variable
 int i;
 for (i = 0; i < numTiles; i++) {
   tiles[i] = createGraphics(tileSize, tileSize, P2D);
   tiles[i].copy(tileset, i*tileSize, 0, tileSize, tileSize, 0, 0, tileSize, tileSize);
 }
}


A slightly related question-- I've got another PGraphics object that I'm drawing the level to so I don't have to re-draw it every frame. When I use the image method to blit tiles from the tile[] array to it, it doesn't respect the alpha channel at all, so pixels with 0 alpha draw as 0xFF000000. if I use image in the same manner to blit directly to the screen it respects alpha, and if I use copy to blit to the buffer it respects alpha. Any reason I can't image() alpha from one PGraphics to another PGraphics?


Thanks to anyone who's willing to help me out, I appreciate your time.
Re: PImage.copy method giving me some flak
Reply #1 - Feb 20th, 2009, 10:29pm
 
General remark: instead of generating an array of PGraphics and draw the ith one, I would choose to make method that just image or copy the ith region of the original tile set to the indicated area.

I don't see the issue you mention about image() between PGraphics not respecting the alpha channel.

My test code to verify this:
Code:
PGraphics pgBack;

void setup()
{
 size(500, 500);
 pgBack = createGraphics(200, 200, P2D);
 PGraphics pgShape = createGraphics(100, 100, P2D);
// Image with transparency
 PImage piIcon = loadImage("icon.png");

 pgShape.beginDraw();
 pgShape.fill(#00BB00);
 pgShape.triangle(10, 50, 90, 80, 50, 10);
 pgShape.endDraw();

 pgBack.beginDraw();
 pgBack.background(200);
 pgBack.fill(#0000AA);
 pgBack.rect(10, 10, 180, 180);
 pgBack.endDraw();

 pgBack.image(pgShape, 10, 10);
 pgBack.image(piIcon, 80, 80);
}

void draw()
{
 background(230);

 image(pgBack, 100, 100);
}

But the triangle is a bit strange in the smaller side (fill color bleeding outside the outline).
Will experiment a bit more on splitting the tileset.
Re: PImage.copy method giving me some flak
Reply #2 - Feb 21st, 2009, 5:43am
 
Hi,

Thank you for the help and advice. I decided to split the tiles to an array first because it builds the environment from a 2D array of tile numbers, and I figured for building bigger environments it would be more efficient to call image from an array than copy specific pixels from a set with a bit of math for each tile.

I managed to duplicate the issue by adding something like what I'm doing to your code. I also added some lines to demonstrate the issue I'm having with copy.

Code:

PGraphics pgBack;
PGraphics pgBackEmpty;

PGraphics iconWithAlpha1;
PGraphics iconWithAlpha2;
PGraphics iconWithAlpha3;


void setup()
{
 size(500, 500);
 pgBack = createGraphics(200, 90, P2D);
 pgBackEmpty = createGraphics(200, 90, P2D);

 // Image with transparency
 PImage piIcon = loadImage("icon.png");

 //three PGraphics objects that will demonstrate the oddities I've observered in the PGraphics.copy method.
 iconWithAlpha1 = createGraphics(piIcon.width, piIcon.height, P2D);
 iconWithAlpha2 = createGraphics(piIcon.width, piIcon.height, P2D);
 iconWithAlpha3 = createGraphics(piIcon.width, piIcon.height, P2D);
 
 
 iconWithAlpha1.copy(piIcon, 0, 0, piIcon.width, piIcon.height, 0, 0, piIcon.width, piIcon.height);
 //This will not copy the entire source-- instead, it will copy as though piIcon.width-1 and piIcon.height-1
 //were specified as source dimensions, and thus, it will stretch them to fit the 1 pixel larger destination.
 
 iconWithAlpha2.copy(piIcon, 0, 0, piIcon.width, piIcon.height, 0, 0, piIcon.width-1, piIcon.height-1);
 //This will take the same parameters as above, but given the smaller destination, no scaling will occur
 
 iconWithAlpha3.copy(piIcon, 0, 0, piIcon.width-1, piIcon.height-1, 0, 0, piIcon.width-1, piIcon.height-1);
 //This will produce the same result as number 2, and will be true to the parameters entered.
 
 //image(iconWithAlpha1, 0, 0);
 //image(iconWithAlpha2, 0, 32);
 //image(iconWithAlpha2, 0, 64);
 
 
 pgBack.beginDraw();
 pgBack.background(200);
 pgBack.endDraw();

 //Example of using copy to blit a PGraphics object with transparency to a PGraphics object already filled by background()
 pgBack.image(iconWithAlpha1, 0, 0);
 pgBack.image(iconWithAlpha2, 0, 32);
 pgBack.image(iconWithAlpha3, 0, 64);

 //Example of using copy to blit a PGraphics object with transparency to a PGraphics not yet filled by background()
 pgBackEmpty.image(iconWithAlpha1, 0, 0);
 pgBackEmpty.image(iconWithAlpha2, 0, 32);
 pgBackEmpty.image(iconWithAlpha3, 0, 64);


}

void draw()
{
 background(127);
 
 //Blitting directly to screen
 image(iconWithAlpha1, 0, 0);
 image(iconWithAlpha2, 0, 32);
 image(iconWithAlpha2, 0, 64);
 //Transparency is preserved, but it would be too much to blit
//every tile every frame.
 
 
 //Blitting from a PGraphics that's had background() run on it.
 image(pgBack, 0, 96);
 //Transparency is preserved between the iconWithAlphas and pgBack, but since the pixels on pgBack were already full and opaque,
 //the transparency doesn't make it to the screen.
 
 //Blitting from a PGraphics that did not have background run on it.
 image(pgBackEmpty, 0, 192);
 //Transparency is apparently discarded between the iconWithAlphas and pgBackEmpty, or the pixels that are transparent
 //are simply not copied at all and the pixels on pgBackEmpty that were never set are defaulted to opaque #000000 in
 //pgBackEmpty.
 
}



I put my comments on what I think is happening in the draw method, but they're just guesses, I'm not good enough to actually mess around in the Java end of things.

I don't think it is, but it could be the png I'm using. I last saved it from an older copy of Photoshop, so it should be up to standards, but I'm also on a Mac, and they love to mess around with images.
Re: PImage.copy method giving me some flak
Reply #3 - Feb 21st, 2009, 10:11pm
 
Indeed, the result is a bit strange. Looks like some bug.
I have, too, a code (made to produce a test tileset) with an unexpected result:
Code:
  PImage alarm = loadImage("Alarm.gif");
PImage cancel = loadImage("Cancel.png");

// We draw on a PGraphics, so background is transparent
PGraphics pg = createGraphics(320, 320, P2D);
pg.beginDraw();
int count = 0;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (count % 3 == 0)
{
// Plain semi-transparent square, no border
pg.noStroke();
pg.fill(count % 2 == 0 ? 0xA000FF00 : 0x800000FF);
pg.rect(i*64, j*64, 64, 64);
}
else
{
// No background, just a double border to visualize the square
pg.noFill();
pg.stroke(count % 2 == 0 ? #FFFF00 : #FF8000);
pg.rect(i*64 + 1, j*64 + 1, 61, 61);
pg.stroke(count % 2 == 0 ? 0 : #0000FF);
pg.rect(i*64, j*64, 63, 63);
}
// Add icon with transparent background
int p = count % 7;
if (p == 0)
{
pg.image(alarm, i*64 + 8, j*64 + 8);
}
else if (p == 3)
{
pg.image(cancel, i*64 + 8, j*64 + 8);
}
count++;
}
}
pg.endDraw();
pg.save("Tileset.png");

exit();

When drawing the image on the PGraphics without background, the transparency becomes black. It is OK on the parts with background.
Re: PImage.copy method giving me some flak
Reply #4 - Feb 22nd, 2009, 7:47pm
 
After running your code, I came up with this:

Code:

PGraphics pg;
PImage transparentImage;

void setup () {
size (200, 200);
pg = createGraphics(100, 100, P2D);
transparentImage = loadImage("Cancel.png");

pg.background(0x00FF0000);
pg.image(transparentImage, 15, 15);

image(pg, 0, 0);
}


It makes a PGraphics and fills it up with pixels with 0 alpha. When you use image to draw a transparent PImage to it, the pixels with 0x00 alpha don't copy RGB values, but copy an alpha of 0xFF, so whatever RGB you gave the background method shows up at full alpha.

I'm inclined to agree that there may be a bug with image.
Re: PImage.copy method giving me some flak
Reply #5 - Feb 23rd, 2009, 8:04am
 
Spork wrote on Feb 21st, 2009, 5:43am:
it would be more efficient to call image from an array than copy specific pixels from a set with a bit of math for each tile.

I disagree here. The math is simplistic, and the time spent to compute it is much smaller than the time to copy the image data! Even adding the overhead of a function call is near zero. Don't underestimate Java. Smiley In another thread, we found that apparently logical optimizations can lead to slower code!
Beside, it will workaround the problems you have.

Back to the bug(s), I suggest, if you haven't done yet, to fill a bug report in the bugs database, with reference to this thread for sample code.
Re: PImage.copy method giving me some flak
Reply #6 - Feb 23rd, 2009, 9:12pm
 
PhiLho  wrote on Feb 23rd, 2009, 8:04am:
I disagree here. The math is simplistic, and the time spent to compute it is much smaller than the time to copy the image data! Even adding the overhead of a function call is near zero. Don't underestimate Java. Smiley In another thread, we found that apparently logical optimizations can lead to slower code!
Beside, it will workaround the problems you have.

Back to the bug(s), I suggest, if you haven't done yet, to fill a bug report in the bugs database, with reference to this thread for sample code.


Right then, I'll see about writing it like that. Given the size of things I'll be working with, either way will probably do fine. As for a bug report, I'll drop them a line right after this.
Page Index Toggle Pages: 1