バイナリ透明度を表現する方法は?
-
06-07-2019 - |
質問
最近、メモリ内の非圧縮ビットマップの表現に興味がありました。ただし、適切に実装する方法がわからないことの1つは、バイナリ透過性です。たとえば、私は次のようなものから始めます:
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;
};
しかし、それは少し無駄に思えます(完全なアルファチャネルを追加することもできます)。私が考えることができる他の唯一の可能性は、色の1つを透明として予約することですが、その色を表示する機能を失います。これを行う標準的な方法はありますか?
一般的な形式(GIF、8ビットPNGなど)はこれをどのように表しますか?
解決
1600万色がありますが、そのうちの1つを透明に指定することは大きな苦労ではありません。画像が16メガピクセルでない限り、16Mのすべての色を使用しないことを確認できます。使用しない色を選択して、透明色にします。それらすべてを使用する巨大なイメージがある場合は、使用頻度が最も低いイメージを選択し、隣接する色に変更して、未使用にします。
ご指摘のとおり、ピクセルRGBデータを使用してピクセルごとに1ビットを保存しようとしても効率的ではありません。 1つのポインターにすべてのRGBピクセルを保存してから、別のポインターに同じHおよびV次元のビットマップを保存するか、クロマキーイングを実行する必要があります。上記のように、R、G、Bおよび透明度ビットマップを使用してデータを別々に保存することもできますが、それを描画することになると、一般的に非常に非効率的です。
他のヒント
Gifは指定された色を透明に使用します。 (例:0xFFFF00が透明だとすると、この色のピクセルはすべて透明として表示されます。)この色はこの画像では使用できません。
Pngにはアルファチャネルがあります。これは、ピクセルのアルファ値を表す別のintを意味します。 (例:0 =完全に透明、255 =不透明、128 =半透明)
通常、透明度を表す4番目のアルファチャネルがあります。
i.e。 RBGの代わりに、RGBAを使用できます。
バイナリ透明度は、クロマキーイングとも呼ばれます。色を透明色として指定し、描画関数で色がクロマキーでない場合はピクセルを描画します(指定された透明色)。
ドロップシャドウなどのマルチレベル透明度を行う場合、ピクセルごとのアルファが使用されます。
透明度を個別のメモリに保存するか、各チャンネルを個別に保存することもできます。例:
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;
}
ビットへのアクセスは最適化できます。これは単なる例です。
別の解決策:カラーチャネルの1つをスワイプし、次のように構造体を定義できます。
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);