Como representar a transparência binário?
-
06-07-2019 - |
Pergunta
Ultimamente eu tenho interesse em representar bitmaps descompactado na memória. No entanto, uma coisa que eu não tenho certeza de como implementar corretamente é a transparência binário. Por exemplo, eu começar com algo como isto:
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. */
};
Eu suponho que a maneira mais simples seria a seguinte:
struct RGBPixel {
uint8_t red;
uint8_t green;
uint8_t blue;
bool transparent;
};
Mas isso parece um desperdício de bits (assim como você pode adicionar um canal alfa completo). A única outra possibilidade que eu posso pensar é para reservar uma das cores como sendo transparente, mas, em seguida, você perde a capacidade de exibir essa cor. Existe uma maneira padrão para fazer isso?
Como fazer formatos comuns (GIF, 8-bit PNG, etc.) representam isso?
Solução
Existem 16 mil cores, designando um deles como vontade transparente não ser um grande sofrimento. A menos que sua imagem é de 16 megapixels, você pode ter certeza que nem sequer usar todas as cores 16M de qualquer maneira, basta escolher um que não é usado e torná-la a cor transparência. Se você tem uma imagem grande que usa-los todos, selecionar o que é menos usado e alterá-lo para uma cor adjacente, tornando-se não utilizado.
Como você indicou, tentando armazenar um único bit por pixel com os dados de pixel RGB não é eficiente. Você provavelmente deve armazenar todos os pixels do RGB em um ponteiro e, em seguida, um bitmap das mesmas H e V dimensões em outro ponteiro, ou você pode fazer chroma key. Você pode armazenar os dados com R, G, B e bitmap transparência separadamente, como mencionado acima, mas que geralmente é muito ineficiente quando se trata de desenhá-lo.
Outras dicas
Gif usa uma cor especificada para transparente. (Por exemplo .: digamos 0xFFFF00 é transparente, para que todos os pixels com esta cor será exibido como transparente.) Esta cor não poderia ser usado nesta imagem.
PNG tem um canal alfa, o que significa uma outra int que representa o valor alfa do pixel. (Por exemplo: 0 = totalmente transparente, opaco 255 =, 128 = semi-transparente)
Normalmente existe um quarto canal alfa para representar a transparência.
i. em vez de RBG, você pode ter RGBA.
binário também é chamado Chroma Keying. Você designa uma cor como a cor transparente e em sua função de desenho desenhar um pixel se a sua cor não é a chave chroma (cor transparente designado).
Por alfa pixel é usado quando você faz transparência multi-nível, como sombras.
Você pode armazenar a transparência na memória separado, ou mesmo armazenar cada canal separadamente, por exemplo:.
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;
};
Em seguida, alocar width*height / 8
bytes para o canal de transparência, e assumindo 8 bits por canal de cor você pode acessar os bits assim:
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, acessar os bits podem ser otimizados, este é apenas um exemplo.
Outra solução: você pode roubar um pouco de um dos canais de cor, e definir a sua estrutura como esta:
struct RGBPixel {
uint8_t red : 7;
uint8_t transparency : 1;
uint8_t green;
uint8_g blue;
};
Quando guardar ou lendo o canal vermelho, você tem que escala em conformidade, por exemplo, red = (uint8_t)( ( (uint16_t)pix->red * 8 ) / 7 );