Question

Lately I've been interested in representing uncompressed bitmaps in memory. However, one thing I'm not sure how to implement properly is binary transparency. E.g., I start out with something like this:

struct RGBPixel {
 uint8_t red;
 uint8_t green;
 uint8_t blue;
};

struct bitmap {
 struct RGBPixel *data;
 size_t width;
 size_t height;
 size_t bytesPerPixel;
 size_t bytewidth;
 /* etc. */
};

I suppose the simplest way would be this:

struct RGBPixel {
 uint8_t red;
 uint8_t green;
 uint8_t blue;
 bool transparent;
};

But that seems a bit wasteful (you might as well add a full alpha channel). The only other possibility I can think of is to reserve one of the colors as being transparent, but then you lose the ability to display that color. Is there a standard way to do this?

How do common formats (GIF, 8-bit PNG, etc.) represent this?

Was it helpful?

Solution

There are 16M colors, designating one of them as transparent will not be a big hardship. Unless your image is 16 megapixels, you can be sure it doesn't even use all 16M colors anyway, just pick one that isn't used and make it the transparency color. If you do have a huge image that uses them all, select the one that is least used and change it to an adjacent color, making it unused.

As you indicated, trying to store a single bit per pixel with the pixel RGB data isn't efficient. You should probably either store all the RGB pixels in one pointer and then a bitmap of the same H and V dimensions in another pointer, or you can do chroma keying. You could store the data with R,G,B and transparency bitmap separately as mentioned above but that's generally very inefficient when it comes to drawing it.

OTHER TIPS

Gif uses a specified color for transparent. (e.g.: lets say 0xFFFF00 is transparent, so all pixels with this color will be display as transparent.) This color could not be used in this image.
Png has an alpha channel, that means another int which represents the alpha value of the pixel. (e.g: 0 = fully transparent, 255 = opaque, 128 = half-transparent)

Commonly there is a fourth Alpha channel to represent transparency.

i.e. instead of RBG, you can have RGBA.

Binary transparency is also called Chroma Keying. You designate a colour as the transparent colour and in your drawing function draw a pixel if its colour is not the chroma key ( designated transparent colour).

Per pixel alpha is used when you do multi-level transparency such as drop shadows.

You could store the transparency in separate memory, or even store each channel separately, e.g.:

struct bitmap {
 uint8_t *red;
 uint8_t *green;
 uint8_t *blue;
 uint8_t *transparency;
 // or packed: uint8_t *RGB, *transparency;
 size_t width;
 size_t height;
};

Then allocate width*height / 8 bytes for the transparency channel, and assuming 8 bits per color channel you can access the bits like this:

bool get_transparency( struct bitmap* bmp, size_t x, size_t y ) {
  size_t idx = y * bmp->width + x;
  size_t tidx = idx >> 3; // = idx / 8
  uint8_t t8 = (uint8_t)( idx & 7 ); // = idx % 8
  uint8_t mask = 1 << t8;
  return ( bmp->transparency[tidx] & mask ) != 0;
}

Note, accessing the bits can be optimized, this is just an example.

Another solution: you could swipe a bit of one of the color channels, and define your struct like this:

struct RGBPixel {
 uint8_t red : 7;
 uint8_t transparency : 1;
 uint8_t green;
 uint8_g blue;
};

When storing or reading the red channel, you have to scale accordingly, e.g. red = (uint8_t)( ( (uint16_t)pix->red * 8 ) / 7 );

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top