Alpha of Zero in first pixel makes whole image opaque

When I use an image as a background, then set the alpha values for all pixels in a second image to something low, then draw that image, I can see “through” the second image to the background, just as I would expect. Here, the mandrill is the second image, with alpha set to 0x40 for every pixel:

If I set alpha to 0x00 for the very first pixel, the entire mandrill becomes opaque:

I’m using Processing 3.5.4. Here’s my code:

PImage imgFace;
PImage imgMandrill;

void setup()
{
  size(480, 480);
  imgFace = loadImage("Face.png");
  imgMandrill = loadImage("Mandrill.png");

  imgMandrill.loadPixels();

  for(int p = 0; p < imgMandrill.pixels.length; ++p)
  {
    imgMandrill.pixels[p] = (imgMandrill.pixels[p] & 0xFFFFFF) | 0x40000000;
  }
    
  imgMandrill.pixels[0] = imgMandrill.pixels[0] & 0xFFFFFF;
  
  imgMandrill.updatePixels();
}

void draw()
{
  background(imgFace);
  image(imgMandrill, 0, 0);
}

I would have expected changing the alpha of one pixel, particularly the upper-left corner, to make virtually no visible difference. Indeed, if I set the alpha of any other pixel to zero, the faint mandrill looks the same as in the first image.

Why does setting the first pixel’s alpha to zero result in the entire image being drawn as though all alpha values were 255?

2 Likes

Turns out that the mandrill image file loads as format RGB, even though you do have to use a full four-byte int for each pixel, and the javadoc advises keeping 0xFF in the high byte. I don’t know if this is safe, but setting the format to ARGB after loading the image makes the problem go away. A safer play would probably be to create an ARGB format image of the same dimensions and copy its pixel data from the RGB image to the new image.

Here’s my code with one line added to set the format. Anyone know whether or not this is safe?

PImage imgFace;
PImage imgMandrill;

void setup()
{
  size(480, 480);
  imgFace = loadImage("Face.png");
  imgMandrill = loadImage("Mandrill.png");
  imgMandrill.format = ARGB;
  imgMandrill.loadPixels();

  for(int p = 0; p < imgMandrill.pixels.length; ++p)
  {
    imgMandrill.pixels[p] = (imgMandrill.pixels[p] & 0xFFFFFF) | 0x40000000;
  }
    
  imgMandrill.pixels[0] = imgMandrill.pixels[0] & 0xFFFFFF;
  
  imgMandrill.updatePixels();
}

void draw()
{
  background(imgFace);
  image(imgMandrill, 0, 0);
}
5 Likes