Alpha叠加
Posted foruok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Alpha叠加相关的知识,希望对你有一定的参考价值。
学习过程中的记录,供参考。
foruok原创,转载请保留出处。欢迎关注微信订阅号“程序视界”。
Alpha值的含义
对于 RGBA(或 BGRA )数据, Alpha 通道中存储的 Alpha 值,实际上应该是 Opaque 值,即不透明度。当 Alpha 值为 255 时,表示不透明; Alpha 值为 0 时,表示全透明。
Alpha 值也经常用 0 ~ 1 这个区间的数字来表示。 0 表示全透明, 1 表示不透明。详见这里:https://en.wikipedia.org/wiki/Alpha_compositing。
直接 Alpha 和预乘 Alpha 的区别
Alpha 模式有两种,直接 Alpha 和预乘 Alpha 。
使用直接 Alpha 描述 RGBA 颜色时,颜色的 Alpha 值会存储在 Alpha 通道中。例如,若要描述具有 60% 不透明度的绿色,请使用以下值:(0 , 255 , 0 , 255 * 0.6) = (0 , 255 , 0 , 153)。值 255 指示全绿, 153(255 的 60%)指示颜色应具有 60% 的不透明度。
使用预乘 Alpha 描述 RGBA 颜色时,每种颜色都会与 Alpha 值相乘:(0 * 0.6, 255 * 0.6 , 0 * 0.6 , 255 * 0.6) = (0 , 153 , 0 , 153)。同时 Alpha 值也会存储在 Alpha 通道中。
RGBA图像数据叠加
我只考虑一幅带 Alpha 效果的图像叠加在背景上的情况。
假设背景图像是 B ,无透明效果,带透明效果的图像是 A ,那么透过 A 去看 B ,看上去的图象 C 就是 A 和 B 的混合图象。
假设 A 图像的透明度为 alpha ,则图像 C 的混合公式如下:
R(C) = alpha * R(A) + (1 - alpha) * R(B)
G(C) = alpha * G(A) + (1 - alpha) * G(B)
B(C) = alpha * B(A) + (1 - alpha) * B(B)
A(C) = 1
混合后的图像 C 的Alpha值为 1 ,所以后面的代码里,直接将结果的 Alpha 值设置为 0xFF 。
基于于 Skia 和 PPAPI 的图像叠加代码
我的一个 PPAPI+Skia 示例,使用 Skia 的 SkBitmap 作为后端来绘图,然后再把 SkBitmap 的数据叠加到 PPAPI 的图像数据上。下面是部分代码:
static void blendFromBgraToRgba(void *srcData, void *destData, struct PP_ImageDataDesc &desc)
{
unsigned char *src = (unsigned char*)srcData;
unsigned char *dst = (unsigned char*)destData;
int len = desc.size.height * desc.stride;
for (int i = 0; i < len; i += 4, src += 4, dst += 4)
{
switch(src[3])
{
case 0:
//do nothing
break;
case 255:
dst[0] = src[2]; //Red
dst[1] = src[1]; //Green
dst[2] = src[0]; //Blue
break;
default:
dst[0] = (((int)dst[0]) * (255 - src[3])) / 255 + src[2]; //Red
dst[1] = (((int)dst[1]) * (255 - src[3])) / 255 + src[1]; //Green
dst[2] = (((int)dst[2]) * (255 - src[3])) / 255 + src[0]; //Blue
break;
}
dst[3] = 0xFF;
}
}
void XXX::init()
{
...
PPB_ImageData * d;
d->Describe(m_image, &m_image_desc);
m_pixels = d->Map(m_image);
...
SkImageInfo ii = SkImageInfo::Make(m_image_desc.size.width,
m_image_desc.size.height,
kBGRA_8888_SkColorType,
kPremul_SkAlphaType,
kLinear_SkColorProfileType);
m_bitmap = new SkBitmap();
m_bitmap->allocPixels(ii, m_image_desc.stride);
...
}
void XXX::paint()
{
....
void *skiaPixels = m_bitmap->getPixels();
blendFromBgraToRgba(skiaPixels, m_pixels, m_image_desc);
...
}
代码有很多可以优化的地方。
参考链接:
就这样吧。
其他参考文章详见我的专栏:【CEF与PPAPI开发】。
以上是关于Alpha叠加的主要内容,如果未能解决你的问题,请参考以下文章
带alpha透明通道视频—网页播放带alpha通道视频叠加合成方案
更改片段(子片段)时 RecyclerView 中的奇怪叠加