【问题标题】:Change DWORD color alpha channel value更改 DWORD 颜色 Alpha 通道值
【发布时间】:2014-08-26 20:51:56
【问题描述】:

我有一个起始颜色:0xffff00ff,即 a:255, r:255, g:0, b:255。

目标是根据百分比将颜色的 Alpha 通道更改为不透明。即该颜色的 50% 不透明度大约为 0x80ff00ff。

我是如何尝试解决的:

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

DWORD nc = cx*cn;

【问题讨论】:

  • 你学过按位运算吗?
  • 是的,但我不确定/不知道我会使用什么作为另一个操作数(?)。即 0xffff00ff | 0xee 什么的。什么都没有给出想要的结果。
  • 使用按位运算提取 R G 和 B 值。根据您从第一步获得的整数执行调整。然后将它们打包回原始字节结构。例如,要提取a 的位,您需要使用按位and 操作cx & ff000000。然后要将其作为 int 获得,您必须向右移动 6 个字节。
  • 好吧,你可以把问题分成更小的问题。其中之一是获得最重要的字节。接下来是将该字节乘以百分比。最后,设置最高有效字节。获取和设置最高有效字节是常见操作。
  • 尝试无符号算术。这对位级的东西很有用。

标签: c++ winapi dword


【解决方案1】:

我将您的问题理解为:我希望将给定的 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 or 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 组件以达到所需的结果。

【讨论】:

    【解决方案2】:

    我选择的解决方案:

    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;
    }
    

    【讨论】:

    • 制作 newAlpha,r,g,b DWORDs 稍微好一点。然后在第二部分中没有符号移位或太大移位的问题。
    【解决方案3】:
    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;
    }
    

    【讨论】:

      【解决方案4】:

      这是经过测试的代码(在 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;
      
      }
      

      【讨论】:

        【解决方案5】:
        DWORD cx = 0xffff00ff;
        float cn = .5;
        DWORD alphaMask=0xff000000;
        DWORD nc = (cx|alphaMask)&((DWORD)(alphaMask*cn)|(~alphaMask));
        

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

        【讨论】:

          猜你喜欢
          • 2015-08-27
          • 2015-06-29
          • 1970-01-01
          • 2011-06-11
          • 1970-01-01
          • 1970-01-01
          • 2013-07-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多