由于alpha值的原因,将一个图像混合到另一个图像会产生不正确的图像

Blending one image onto another gives incorrect image because of alpha value

本文关键字:图像 混合 一个 另一个 不正确 alpha 由于      更新时间:2023-10-16

所以我遇到了将两个图像混合在一起处理透明度的问题。我在这里使用freetype来生成字形。我有一个相当大的代码库,所以我挑选了混合过程中涉及的代码的主要部分。

这是我正在使用的代码:

void TopDown(FT_Bitmap *bitmap, ... )
{
.....
.....
for (int srcY=0; srcY < bitmap->rows; srcY++, destLine += textureWidth, srcLine += bitmap->pitch)
{
unsigned char *currSrc = srcLine;
unsigned int *currDest = destLine;
for (int srcX=0; srcX < bitmap->width; srcX++, currSrc++)
{
unsigned char alpha = *currSrc * textA / 255;
if (currDest >= dest && currDest < destMax)
{
unsigned int destR = (textR * alpha + bgR * (255-alpha))/255;
unsigned int destG = (textG * alpha + bgG * (255-alpha))/255;
unsigned int destB = (textB * alpha + bgB * (255-alpha))/255;
unsigned int as = alpha;
*currDest = makeColor(destR, destG, destB, alpha);
}
currDest++;
}
}
}

让我们把这条线unsigned char alpha = *currSrc * textA / 255分成两行:

unsigned char alpha = *currSrc;
alpha = alpha * textA / 255;

这实际上是取红色成分。您必须跳过3个字节才能获得alpha值:

unsigned char alpha = *currSrc + 3;
alpha = alpha * textA / 255;

不过你其实并不需要。只需找到所有的黑色像素,并将它们的alpha值设置为零。请确保文本颜色不是黑色。您可以使用0x00000001作为文本颜色,这将使其与黑色背景不同。

void TopDown(...)
{
...
for(...)
{
...
for(...)
{
...
unsigned char r = *currSrc + 0;
unsigned char g = *currSrc + 1;
unsigned char b = *currSrc + 2;
unsigned char alpha = 128; //or 255 or whatever
if(currDest >= dest && currDest < destMax)
{
if(r || g || b)
{
//non-black pixels get alpha value
*currDest = makeColor(r, g, b, alpha);
}
else
{
//black pixels get zero alpha
*currDest = 0;
}
}
currDest++;
}
}
}

现在您只需要在背景位图上绘制即可。如果使用了正确的绘制功能,则不需要进行混合。背景将显示为透明。手动混合颜色:

unsigned char blend2(unsigned char m, unsigned char n, unsigned char alpha)
{
float i = (float)n;
float j = (float)m;
float a = (float)alpha;
j *= a / 255.0f; //you can skip this step
int color = (int)((i + j)/2);
return (unsigned char)color;
}
void blendBitmap(...)
{
...
for (int line=0; line < copyHeight; line++)
{
T *destPtr = destBitmap->line(line+destRow) + 4*destCol;
unsigned char *sourcePtr = sourceBitmap->line(line+srcRow) + 4*srcCol;
if(destPtr && sourcePtr)
{
for (int col=0; col < copyWidth; col++, destPtr += 4, sourcePtr += 4)
{
unsigned char alpha = sourcePtr[3];
destPtr[0] = blend2(destPtr[0], sourcePtr[0], alpha);
destPtr[1] = blend2(destPtr[1], sourcePtr[1], alpha);
destPtr[2] = blend2(destPtr[2], sourcePtr[2], alpha);
}
}
}
}