views:

112

answers:

5

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?

+1  A: 

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)

Hippo
Which color does it use?
Sam
Gif uses indexed color, not direct color. So each pixel is encoded as one of 256 different colors which is an index into an rgb color lookup table. If you want to have transparency, you simply reduce the image to 255 colors and then the remaining index is used to indicate transparency.
Southern Hospitality
that right @ Southern Hospitality, I only wanted to show the 2 ways to define certain pixels transparent.
Hippo
I wasn't modifying your comment, Hippo, I was responding to Sam. The "color" GIF uses isn't really a color, because it's an index into a table and there's no color assigned to that index in the table.
Southern Hospitality
A: 

Commonly there is a fourth Alpha channel to represent transparency.

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

Andy
A: 

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.

Indeera
A: 

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 );

frunsi
+1  A: 

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.

Southern Hospitality
"just pick one that isn't used and make it the transparency color." But how do I pick this color? Loop through the image and keep guessing at a color until I find one that isn't in use?
Sam
Start with a color you think won't be used. Loop through, if it is used, remember the offset withing the pixmap where you are, change the color slightly (perhaps increment the B value, rolling through G to R as appropriate) and then loop down to the end of the pixmap, and start at the start again, if you don't find this color, it's the one. Otherwise, repeat.For better corner case performance, select 256 colors you don't think will be used at the start and search them simultaneously. The chances of finding all are in use is pretty low, in a 4MP image, it's 1/4^256 or about 1 in 1e25.
Southern Hospitality