【问题标题】:Applying a transparent gradient from left to right in C/C++在 C/C++ 中从左到右应用透明渐变
【发布时间】:2014-11-13 21:36:38
【问题描述】:

我正在尝试在 C/C++ 中创建一种算法,它将从左到右的均匀透明渐变应用于像素缓冲区。如下图所示:

接下来是我的实现。但生成的图像甚至不接近我需要实现的目标。任何人都可以发现我做错了什么?谢谢

void alphaGradient(uint32_t* pixelsBuffer, const int width, const int height)
{
    const short OPAQUE = 255;
    int pixelOffsetY, pixelIndex;
    short A, R, G, B;

    for (int y = 0; y < height; y++)
    {
        A = OPAQUE;

        pixelOffsetY = y * height;

        for (int x = 0; x < width; x++)
        {
            pixelIndex = pixelOffsetY + x;

            A = (int)(OPAQUE - ((OPAQUE * x) / width));
            R = (pixelsBuffer[pixelIndex] & 0x00FF0000) >> 16;
            G = (pixelsBuffer[pixelIndex] & 0x0000FF00) >> 8;
            B = (pixelsBuffer[pixelIndex] & 0x000000FF);

            pixelsBuffer[pixelIndex] = (A << 24) + (R << 16) + (G << 8) + B;
        }
    }
}

【问题讨论】:

  • 结果与您的预期有何不同?代码乍一看还不错。
  • 您正在大量混合类型。在A 上,您将强制转换为有符号值,而(A &lt;&lt; 24) 在这里您将short 移动了24 个字节。这不是未定义的行为吗?也许没关系,但在某些时候转换相当棘手。
  • 你犯了一个简单的错误:pixelOffsetY = y * height; 应该是pixelOffsetY = y * width;
  • @luk32: 24 个职位
  • @luk32 我认为通常的整数促销将在这里发挥作用,所以从short 开始应该不会受到伤害。但是制作所有东西 uint32_t 将是一个快速测试来确保。

标签: c++ c bitmap gradient transparent


【解决方案1】:

我还没有尝试过这段代码,但这样的东西应该可以工作:

void alphaGradient(uint32_t* pixelBuffer, const int width, const int height)
{
for (int i = 0; i < width; i++)
{
    for (int j = 0; j < height; j++)
    {
        const DWORD src = pixelBuffer[i + j * width];
        const DWORD dst = MYBACKGROUNDCOLOR;

        const unsigned char src_A = (width - i) * 255 / width;
        const unsigned char src_R = (src & 0x00FF0000) >> 16;
        const unsigned char src_G = (src & 0x0000FF00) >> 8;
        const unsigned char src_B = (src & 0x000000FF);

        //const unsigned char dst_Alpha = (src & 0xFF000000) >> 24;
        const unsigned char dst_R = (dst & 0x00FF0000) >> 16;
        const unsigned char dst_G = (dst & 0x0000FF00) >> 8;
        const unsigned char dst_B = (dst & 0x000000FF);

        const unsigned char rlt_R = (src_R * src_A + dst_R * (255 - src_A)) / 255;
        const unsigned char rlt_G = (src_G * src_A + dst_G * (255 - src_A)) / 255;
        const unsigned char rlt_B = (src_B * src_A + dst_B * (255 - src_A)) / 255;
        //pixelBuffer[i + j*width] = (DWORD)(((255) << 24) | (((rlt_R)& 0xff) << 16) | (((rlt_G)& 0xff) << 8) | ((rlt_B)& 0xff));
        // or if you want to save the transparancy then 
        //pixelBuffer[i + j*width] = (DWORD)(((src_A) << 24) | (((src_R)& 0xff) << 16) | (((src_G)& 0xff) << 8) | ((src_B)& 0xff));
    }

}
}

但就个人而言,我会尝试为此使用 DirectX 或 OpenGL,并编写一个好的 PixelShader。它会让这个 ALOT 更快。

【讨论】:

  • 完美。确实按预期工作。
  • 在这种情况下,您正在预乘颜色。这可能不是用户正在寻找的......这在很大程度上取决于以后对图像所做的事情,但我认为这个问题并没有说明改变颜色的任何内容。
  • 你对我的 src_A 是正确的,它应该是 (width - i) * 255 / width;正如您所说,“这在很大程度上取决于以后对图像所做的事情”。如果您在我的代码末尾检查我的两个 cmets,我写了两个不同的代码行,第一个是保存混合颜色,第二个是保存透明度,然后我希望用户删除 dst_X 和 rlt_X。跨度>
【解决方案2】:

作为建议,由于您只想修改 Alpha 通道,因此无需对颜色进行任何操作。所以以下方法也可以:

char *b((char *) pixelBuffer);
for(int j = 0; j < height; ++j)
{
    for(int i = 0; i < width; ++i, b += 4)
    {
        *b = (width - i) * 255 / width;
    }
}

就是这样。您还可以通过在以下几行中复制第一行的数据来消除每一行的计算:

// WARNING: code expects height > 0!
char *b((char *) pixelBuffer);
for(int i = 0; i < width; ++i, b += 4)
{
    *b = (width - i) * 255 / width;
}
int offset = width * -4;
for(int j = 1; j < height; ++j)
{
    for(int i = 0; i < width; ++i, b += 4)
    {
        *b = b[offset];
    }
}

作为练习,我将把这个双 for() 循环更改为单个 for() 循环,这将使它更快一些(因为您将有一个计数器(变量 b)而不是三)。


请注意,我不明白 Mikael 的答案将如何工作,因为他在计算 Alpha 通道时在错误的位置使用了 * 255。对于整数算术,这非常重要。所以这应该返回 0 或 255:

(width - i) / width * 255

因为如果value &lt; width 那么value / width == 0。而(width - i) 要么是width,要么是小于width 的值...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多