【问题标题】:How to represent binary transparency?如何表示二进制透明度?
【发布时间】:2010-12-21 05:27:19
【问题描述】:

最近我对在内存中表示未压缩的位图很感兴趣。但是,我不确定如何正确实现的一件事是二进制透明度。例如,我从这样的事情开始:

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 等)如何表示这一点?

【问题讨论】:

    标签: c png bitmap transparency gif


    【解决方案1】:

    Gif 使用指定的颜色表示透明。 (例如:假设 0xFFFF00 是透明的,因此具有此颜色的所有像素都将显示为透明。)此颜色无法在此图像中使用。
    Png 有一个 alpha 通道,这意味着另一个 int 表示像素的 alpha 值。 (例如:0 = 完全透明,255 = 不透明,128 = 半透明)

    【讨论】:

    • Gif 使用索引颜色,而不是直接颜色。因此,每个像素都被编码为 256 种不同颜色中的一种,这是 rgb 颜色查找表的索引。如果你想有透明度,你只需将图像减少到 255 种颜色,然后使用剩余的索引来表示透明度。
    • 没错@Southern Hospitality,我只想展示定义某些像素透明的两种方法。
    • 我没有修改你的评论,Hippo,我是在回复 Sam。 GIF 使用的“颜色”并不是真正的颜色,因为它是表格的索引,并且没有为表格中的索引分配颜色。
    【解决方案2】:

    通常有第四个 Alpha 通道来表示透明度。

    即代替 RBG,你可以有 RGBA。

    【讨论】:

      【解决方案3】:

      二进制透明度也称为色度键控。您将一种颜色指定为透明颜色,并在绘图函数中绘制一个像素,如果其颜色不是色度键(指定透明颜色)。

      在进行多级透明度(例如投影)时使用每像素 Alpha。

      【讨论】:

        【解决方案4】:

        您可以将透明度存储在单独的内存中,甚至可以单独存储每个通道,例如:

        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-&gt;red * 8 ) / 7 );

        【讨论】:

          【解决方案5】:

          一共有1600万种颜色,将其中一种指定为透明不会是什么大难事。除非您的图像是 16 兆像素,否则您可以确定它甚至不会使用所有 1600 万种颜色,只需选择一种未使用的颜色并将其设置为透明色。如果您确实有一张使用它们的巨大图像,请选择使用最少的一张并将其更改为相邻的颜色,使其未使用。

          正如您所指出的,尝试使用像素 RGB 数据存储每个像素的单个位效率不高。您可能应该将所有 RGB 像素存储在一个指针中,然后将相同 H 和 V 尺寸的位图存储在另一个指针中,或者您可以进行色度键控。如上所述,您可以将数据与 R、G、B 和透明度位图分开存储,但在绘制数据时通常效率很低。

          【讨论】:

          • "只选择一个没用过的,让它变成透明色。"但是我该如何选择这种颜色呢?循环遍历图像并不断猜测颜色,直到找到一个没有使用的颜色?
          • 从您认为不会使用的颜色开始。循环,如果使用,记住你所在的像素图的偏移量,稍微改变颜色(可能增加B值,适当滚动G到R)然后循环到像素图的末尾,然后开始再次开始,如果你没有找到这个颜色,那就是那个。否则,重复。为了获得更好的极端情况性能,请选择一开始不会使用的 256 种颜色并同时搜索它们。找到所有都在使用的机会非常低,在 4MP 图像中,它是 1/4^256 或 1e25 中的大约 1。
          猜你喜欢
          • 1970-01-01
          • 2020-08-12
          • 2014-07-17
          • 2011-04-07
          • 1970-01-01
          • 1970-01-01
          • 2012-03-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多