最近我对在内存中表示未压缩的位图感兴趣。然而,我不确定如何正确实现的一件事是二进制透明度。例如,我从这样的事情开始:
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. */
};
我想最简单的方法是这样的:
struct RGBPixel {
uint8_t red;
uint8_t green;
uint8_t blue;
bool transparent;
};
但这似乎有点浪费(你不妨添加一个完整的 Alpha 通道)。我能想到的唯一另一种可能性是将其中一种颜色保留为透明,但随后您就失去了显示该颜色的能力。有标准方法可以做到这一点吗?
常见格式(GIF、8位PNG等)如何表示这一点?
有 16M 种颜色,将其中一种指定为透明不会是一个大困难。除非您的图像是 16 兆像素,否则您可以确定它甚至不会使用所有 16M 颜色,只需选择一种未使用的颜色并将其设为透明颜色即可。如果您确实有一张使用所有这些颜色的巨大图像,请选择最少使用的图像并将其更改为相邻颜色,使其不被使用。
正如您所指出的,尝试使用像素 RGB 数据存储每个像素一位的效率不高。您可能应该将所有 RGB 像素存储在一个指针中,然后将相同 H 和 V 尺寸的位图存储在另一个指针中,或者您可以进行色度键控。如上所述,您可以将数据与 R、G、B 和透明度位图分开存储,但这在绘制数据时通常效率非常低。
Gif 使用指定的颜色进行透明。 (例如:假设 0xFFFF00 是透明的,因此具有该颜色的所有像素都将显示为透明。)该颜色无法在此图像中使用。
Png 有一个 alpha 通道,这意味着另一个 int 表示像素的 alpha 值。 (例如:0 = 完全透明,255 = 不透明,128 = 半透明)
二元透明度也称为色度键控。您将一种颜色指定为透明颜色,如果其颜色不是色度键(指定透明颜色),则在绘图函数中绘制一个像素。
当您执行多级透明度(例如阴影)时,将使用每像素 alpha。
通常有第四个 Alpha 通道来表示透明度。
即您可以使用 RGBA 来代替 RBG。
您可以将透明度存储在单独的内存中,甚至可以单独存储每个通道,例如:
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;
};
然后为透明通道分配
width*height / 8
字节,并假设每个颜色通道有 8 位,您可以像这样访问这些位:
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;
}
注意,访问位可以优化,这只是一个示例。
另一种解决方案:您可以滑动其中一个颜色通道的一点,并像这样定义您的结构:
struct RGBPixel {
uint8_t red : 7;
uint8_t transparency : 1;
uint8_t green;
uint8_g blue;
};
存储或读取红色通道时,必须进行相应的缩放,例如
red = (uint8_t)( ( (uint16_t)pix->red * 8 ) / 7 );