Изменить значение DWORD цвет альфа-канала

У меня начальный цвет: 0xffff00ff, а это: 255, r: 255, g: 0, b: 255.

Цель состоит в том, чтобы изменить альфа-канал цвета, чтобы он был менее непрозрачным на основе процента. т.е. непрозрачность 50% для этого цвета примерно равна 0x80ff00ff.

Как я пытался найти решение:

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

DWORD nc = cx*cn;

1

Решение

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

Это должно сделать свое дело. все, что я делаю здесь, это устанавливаю первые 8 битов DWORD на 1 с помощью или (обозначается символом ‘|’), а затем добавляю эти биты с правильным значением, которое вы хотите, чтобы они были, что является временем альфа-маски cn. Конечно, я умножил результат умножения, чтобы снова сделать его DWORD.

2

Другие решения

Это проверенный код (в 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;

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

Я понимаю ваш вопрос следующим образом: я хочу изменить определенный компонент цвета RGBA на определенный коэффициент, сохраняя при этом общую прозрачность.

Для цвета с полной альфа-версией (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. Возможно, вы захотите сохранить некоторые из этих параметров фиксированными и разрешить другим изменять.

Мой подход к этой проблеме заключается в том, чтобы сначала попытаться найти расстояние оттенка между исходным и целевым цветами в полной альфе, а затем преобразовать реальный исходный цвет в HSV, применить изменение оттенка, а затем преобразовать обратно в RGBA. Очевидно, что второй шаг не является необходимым, если альфа фактически равна 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;
}

Обратите внимание, как вышеперечисленное зависит от типа rgba а также hsv иметь неявные конструкторы преобразования. Алгоритмы преобразования можно легко найти с помощью веб-поиска. Также должно быть легко получить определения структуры для hsv из rgba или включить доступ к отдельным компонентам в качестве членов поля (вместо использования [] оператор).
Например:

//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 для достижения желаемого результата.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector