1

I have a starting color: 0xffff00ff, which is a:255, r:255, g:0, b:255.

The goal is to change the alpha channel of the color to be less opaque based on a percentage. i.e. 50% opacity for that color is roughly 0x80ff00ff.

How I've tried to reach the solution:

DWORD cx = 0xffff00ff;
DWORD cn = .5;

DWORD nc = cx*cn;
4

5 回答 5

3
DWORD cx = 0xffff00ff;
float cn = .5;
DWORD alphaMask=0xff000000;
DWORD nc = (cx|alphaMask)&((DWORD)(alphaMask*cn)|(~alphaMask));

这应该可以解决问题。我在这里所做的就是用 or 将 DWORD 的前 8 位设置为 1(由“|”表示),然后将这些位与您希望它们的正确值相加,即 alpha 掩码乘以 cn。当然,我将乘法的结果再次转换为 DWORD。

于 2014-07-06T04:10:43.723 回答
1
typedef union ARGB
{
    std::uint32_t Colour;
    std::uint8_t A, R, G, B;
};


int main()
{
    DWORD cx = 0xffff00ff;
    reinterpret_cast<ARGB*>(&cx)->A = reinterpret_cast<ARGB*>(&cx)->A / 2;

    std::cout<<std::hex<<cx;
}
于 2014-07-06T04:18:53.217 回答
1

这是经过测试的代码(在 linux 中)。但是,您可能会找到一个更简单的答案。注意:这是 RGBA,而不是您在问题中提到的 ARGB。

double transparency = 0.500;

unsigned char *current_image_data_iterator = reinterpret_cast<unsigned char*>( const_cast<char *>( this->data.getCString() ) );
unsigned char *new_image_data_iterator = reinterpret_cast<unsigned char*>( const_cast<char *>( new_image_data->data.getCString() ) );

size_t x;

//cout << "transparency: " << transparency << endl;

for( x = 0; x < data_length; x += 4 ){

    //rgb data is the same
    *(new_image_data_iterator + x) = *(current_image_data_iterator + x);
    *(new_image_data_iterator + x + 1) = *(current_image_data_iterator + x + 1);
    *(new_image_data_iterator + x + 2) = *(current_image_data_iterator + x + 2);

    //multiply the current opacity by the applied transparency
    *(new_image_data_iterator + x + 3) = uint8_t( double(*(current_image_data_iterator + x + 3)) * ( transparency / 255.0 ) );

    //cout << "Current Alpha: " << dec << static_cast<int>( *(current_image_data_iterator + x + 3) ) << endl;
    //cout << "New Alpha: " << double(*(current_image_data_iterator + x + 3)) * ( transparency / 255.0 ) << endl;
    //cout << "----" << endl;

}
于 2014-07-06T04:25:21.367 回答
1

我选择使用的解决方案:

DWORD changeOpacity(DWORD color, float opacity) {
    int alpha = (color >> 24) & 0xff;
    int r = (color >> 16) & 0xff;
    int g = (color >> 8) & 0xff;
    int b = color & 0xff;

    int newAlpha = ceil(alpha * opacity);

    UINT newColor = r << 16;
    newColor += g << 8;
    newColor += b;
    newColor += (newAlpha << 24);


    return (DWORD)newColor;
}
于 2014-07-06T04:57:16.417 回答
0

我将您的问题理解为:我希望将给定的 rgba 颜色分量更改某个因素,同时保持相同的整体透明度。

对于具有完整 alpha(1.0 或 255)的颜色,这是微不足道的:只需将组件相乘而不接触其他组件:

//typedef unsigned char uint8
enum COMPONENT {
    RED,
    GREEN,
    BLUE,
    ALPHA
};

struct rgba {
    uint8 components[4];
    // uint8 alpha, blue, green, red; // little endian
    uint8 &operator[](int index){
        return components[index];
    }
};

rgba color;
if (color[ALPHA] == 255)
   color[RED] *= factor;
else
    ComponentFactor(color, RED, factor);

在一般情况下,这个问题可能没有一个单一的答案。考虑到颜色可以交替编码为HSL 或 HSV。您可能希望将其中一些参数保持固定,并允许其他参数进行更改。

我解决这个问题的方法是首先尝试在全 alpha 处找到源颜色和目标颜色之间的色调距离,然后将真实的源颜色转换为 HSV,应用色调的变化,然后再转换回 RGBA。显然,如果 alpha 实际上是 1.0,则不需要第二步。

在伪代码中:

rgba ComponentFactor(rgba color, int component, double factor){
    rgba fsrc = color, ftgt;
    fsrc.alpha = 1.0; // set full alpha
    ftgt = fsrc;
    ftgt[component] *= factor; // apply factor
    hsv hsrc = fsrc, htgt = ftgt; // convert to hsv color space
    int distance = htgt.hue - hsrc.hue; // find the hue difference
    hsv tmp = color; // convert actual color to hsv
    tmp.hue += distance; // apply change in hue
    rgba res = tmp; // convert back to RGBA space 
    return res;
}

请注意上面如何依赖类型rgbahsv具有隐式转换构造函数。通过网络搜索可以很容易地找到转换算法。从 rgba 派生 hsv 的结构定义也应该很容易,或者将单个组件访问作为字段成员包含在内(而不是使用[]运算符)。例如:

//typedef DWORD uint32;

struct rgba {

    union {
        uint8 components[4];
        struct {
            uint8 alpha,blue,green,red; // little endian plaform
        }
        uint32 raw;
    };

    uint8 &operator[](int index){
        return components[4 - index];
    }
    rgba (uint32 raw_):raw(raw_){}
    rgba (uint8 r, uint8 g, uint8 b, uint8 a):
        red(r), green(g), blue(b),alpha(a){}
};

也许您必须找到色调因子而不是距离,或者调整其他 HSV 组件以达到所需的结果。

于 2014-07-06T04:14:23.700 回答