I'm trying to write my own Color struct for a task I have.
My goal is that my buffer will always contain a RGBA value, even if it is initialized with ARGB values.
I have 2 constructors:
Takes R,G,B,A values of type uint8_t separately - Works like a charm.
Takes a uint32_t that holds an ARGB value - The problem begins here: I'm
I have a method that converts the provided ARGB into RGBA ("fromArgb").
Seems like only the conversion to the RGBA color Red works well, and all other color conversions are invalid.
Examples:
Color red = Color(0xFFFF0000); // Works well (Contains values:
Hex: #FF0000FF; R: 255, G: 0, B: 0, A: 255)
Color green = Color(0xFF008000); // Wrong - Actually Pinkish color
(Contains values: Hex: #008000FF R: 255, G: 0, B: 128, A: 0)
Color blue = Color(0xFF0000FF); // Wrong - Actually Yellowish color
(Contains values: Hex: #0000FFFF R: 255, G: 255, B: 0, A: 0)
Color yellow = Color(0xFFFFFF00); // Wrong - Actually Pinkish color
(Contains values: Hex: #FFFF00FF R: 255, G: 0, B: 255, A: 255)
I can't seem to find the problem.
I'll be more than glad to have some support from the community!
Example source Code:
struct Color
{
public:
/* Works fine!!! */
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255)
{
buffer((r << 0) | (g << 8) | (b << 16) | (a << 24))
}
Color(const uint32_t argb)
{
buffer = fromArgb(argb);
}
inline uint32_t fromArgb(uint32_t argb)
{
return
// Source is in format: 0xAARRGGBB
((argb & 0x00FF0000) << 8) | //RR______
((argb & 0x0000FF00) << 8) | //__GG____
((argb & 0x000000FF) << 8) | //____BB__
((argb & 0xFF000000) >> 24); //______AA
// Return value is in format: 0xRRGGBBAA
}
inline uint8_t getRed(void) const
{
return (buffer >> 0) & 0xFF;
}
inline uint8_t getGreen(void) const
{
return (buffer >> 8) & 0xFF;
}
inline uint8_t getBlue(void) const
{
return (buffer >> 16) & 0xFF;
}
inline uint8_t getAlpha(void) const
{
return (buffer >> 24) & 0xFF;
}
/* Works fine!!!*/
std::string getHex(void) const
{
std::string result = "#";
char colorBuffer[255] = {};
// Order is intentionally end to beginning
sprintf_s(colorBuffer, 255, "%.2X", getAlpha());
result.append(colorBuffer);
sprintf_s(colorBuffer, 255, "%.2X", getBlue());
result.append(colorBuffer);
sprintf_s(colorBuffer, 255, "%.2X", getGreen());
result.append(colorBuffer);
sprintf_s(colorBuffer, 255, "%.2X", getRed());
result.append(colorBuffer);
return result;
}
private:
uint32_t buffer;
}
Looks to me that the class is holding an ABGR value, so obviously a conversion from ARGB to RGBA isn't helpful. This seems right (untested though).
inline uint32_t fromArgb(uint32_t argb)
{
return
// Source is in format: 0xAARRGGBB
((argb & 0x00FF0000) >> 16) | //______RR
((argb & 0x0000FF00)) | //____GG__
((argb & 0x000000FF) << 16) | /___BB____
((argb & 0xFF000000)); //AA______
// Return value is in format: 0xAABBGGRR
}
Related
my current understanding of bitwise operations is that it would push the binary reprisentation of a number a specific amount of times either removing numbers in the process (in case of >>) or add 0's in the end of a number (in case of <<).
so why is it so when i have a int32 storing a hex value of
int32_t color = 0xFFFF99FF; (= 1111 1111 1111 1111 1001 1001 1111 1111)
bitshifting right this int by 24 should give the value FF , because we moved the first two byts by the number of the byts remaining (32 - 8 = 24)
but what actually happens is that i end up with the value -1 when i execute my code and 0 in calculator
note : bitshifting right by 18 yeilds me the desired result.
am using the SDL2 library and C++
am trying to store colors as their hex values then extract the red,green and blue chanel ignoring the alpha one .
the code here is minimized without any unacessary details.
int32_t color; //hex value of the color yellow
//taking input and changing the value of color based on it
if (event->type == SDL_KEYDOWN) {
switch (event->key.keysym.sym)
{
case SDLK_a:
//SDL_SetRenderDrawColor(renderer, 255, 255, 153, 255); // sand
color = 0xFFFF99FF; //hex code for sand color
break;
case SDLK_z:
//SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); // water
color = 0x0000FFFF; //hex code for blue color ...
break;
case SDLK_e:
//SDL_SetRenderDrawColor(renderer, 139, 69, 19, 255); // dirt
color = 0x8B4513FF;
break;
case SDLK_d:
//SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // delete button || air
color = 0x000000FF;
break;
default:
OutputDebugString("unhandled input.\n");
break;
}
}
//checking for mouse input and drawing a pixel with a specific color based on it
if (event-\>button.button == SDL_BUTTON_LEFT)
{
SDL_SetRenderDrawColor(renderer, color \>\> 24, (color \>\> 16) - (color \>\> 24), (color \>\> 8) - ((color \>\> 16) - (color \>\> 24) + color \>\> 24));
OutputDebugString(std::to_string(color \>\> 24).c_str());
SDL_RenderDrawPoint(renderer, mouseX / 4, mouseY / 4);
SDL_RenderPresent(renderer);
}
int32_t is signed and then >> is the signed shift, keeping the sign bit 31. You should use uint32_t. And it also is more logical to use uint8_t for color components.
I'm using ESP8266 to run my smart room over MQTT.
I'm struggling with converting a string to separated RGB integer values.
The string I get looks like this: #953f4f
I've already tried toInt(), atoi(), atol(), casting, etc.
Here is the code:
mqtt.subscribe("light/rgb", [] (const String &payload) {
char msg[payload.length() + 1];
payload.toCharArray(msg, payload.length() + 1);
int r = msg[1];
Serial.println(r);
});
Now I need to find out how to convert ASCII to int.
Unless there's a better way to convert string to an int.
If Arduino has strtol then you can do it like this:
mqtt.subscribe("light/rgb", [] (const String &payload) {
if (payload.length() != 7) {
Serial.printf("invalid payload: '%s'\n", payload.c_str());
return;
}
long rgb = strtol(payload.c_str() + 1, 0, 16); // parse as Hex, skipping the leading '#'
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
Serial.printf("r=%d, g=%d, b=%d\n", r, g, b);
});
I have a monochrome bitmap. I am using it for collision detection.
// creates the monochrome bitmap
bmpTest = new Bitmap(200, 200, PixelFormat1bppIndexed);
// color and get the pixel color at point (x, y)
Color color;
bmpTest->GetPixel(110,110,&color);
// the only method I know of that I can get a 0 or 1 from.
int b = color.GetB();
// b is 0 when the color is black and 1 when it is not black as desired
Is there a faster way of doing this? I can only use it on Get A R G B() values. I am using GetB() because any ARGB value is 0 or 1, correctly, but seems messy to me.
Is there a way I can read a byte from a monochrome bitmap returning either a 0 or 1? (is the question)
You should use LockBits() method for faster access:
BitmapData bitmapData;
pBitmap->LockBits(&Rect(0,0,pBitmap->GetWidth(), pBitmap->GetHeight()), ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData);
unsigned int *pRawBitmapOrig = (unsigned int*)bitmapData.Scan0; // for easy access and indexing
unsigned int curColor = pRawBitmapCopy[curY * bitmapData.Stride / 4 + curX];
int b = curColor & 0xff;
int g = (curColor & 0xff00) >> 8;
int r = (curColor & 0xff0000) >> 16;
int a = (curColor & 0xff000000) >> 24;
I'm currently attempting to create a color gradient class for my Mandelbrot Set explorer.
It reads the color constraints (RGBA8888 color and position between 0 and 1) from a text file and adds them to a vector, which is lateron used to determine colors at a certain position.
To compute a color, the algorithm searches the next constraint to either side from the given position, splits the color into the four single channels, and then, for each one, searches the lower of both and adds a portion of the difference equal to the ratio (x-lpos)/(upos-lpos) to the lower color. Afterwards, the channels are shifted and ORed together, and then returned as RGBA8888 unsigned integer. (See the code below.)
EDIT: I completely rewrote the gradient class, fixing some issues and making it more readable for the sake of debugging (It gets slow as hell, though, but -Os more or less takes care of that). However, It's still not as it's supposed to be.
class Gradient { //remade, Some irrelevant methods and de-/constructors removed
private:
map<double, unsigned int> constraints;
public:
unsigned int operator[](double value) {
//Forbid out-of-range values, return black
if (value < 0 || value > 1+1E-10) return 0xff;
//Find upper and lower constraint
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
//lower color channels
unsigned char lred = (lowerC->second >> 24) & 0xff;
unsigned char lgreen = (lowerC->second >> 16) & 0xff;
unsigned char lblue = (lowerC->second >> 8) & 0xff;
unsigned char lalpha = lowerC->second & 0xff;
//upper color channels
unsigned char ured = (upperC->second >> 24) & 0xff;
unsigned char ugreen = (upperC->second >> 16) & 0xff;
unsigned char ublue = (upperC->second >> 8) & 0xff;
unsigned char ualpha = upperC->second & 0xff;
unsigned char red = 0, green = 0, blue = 0, alpha = 0xff;
//Compute each channel using
// lower color + dist(lower, x)/dist(lower, upper) * diff(lower color, upper color)
if (lred < ured)
red = lred + (value - lpos)/(upos - lpos) * (ured - lred);
else red = ured + (upos - value)/(upos - lpos) * (ured - lred);
if (lgreen < ugreen)
green = lgreen + (value - lpos)/(upos - lpos) * (ugreen - green);
else green = ugreen + (upos - value)/(upos - lpos) * (ugreen - lgreen);
if (lblue < ublue)
blue = lblue + (value - lpos)/(upos - lpos) * (ublue - lblue);
else blue = ublue + (upos - value)/(upos - lpos) * (ublue - lblue);
if (lalpha < ualpha)
alpha = lalpha + (value - lpos)/(upos - lpos) * (ualpha - lalpha);
else alpha = ualpha + (upos - value)/(upos - lpos) * (ualpha - lalpha);
//Merge channels together and return
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
void addConstraint(unsigned int color, double position) {
constraints[position] = color;
}
};
Usage in the update method:
image[r + rres*i] = grd[ratio];
//With image being a vector<unsigned int>, which is then used as data source for a `SDL_Texture` using `SDL_UpdateTexture`
It only works partially, though. When I only use a black/white gradient, the resulting image is as intended:
Gradient file:
2
0 000000ff
1 ffffffff
However, when I use a more colorful gradient (a linear version of the Ultra Fractal gradient, input file below), the image is far from the intended result the image still doesn't show the desired coloring:
Gradient file:
5
0 000764ff
.16 206bcbff
.42 edffffff
.6425 ffaa00ff
0.8575 000200ff
What am I doing wrong? I've rewritten the operator[] method multiple times, without anything changing.
Questions for clarification or general remarks on my code are welcome.
Your problem is due to an over-complicated interpolation function.
When linearly interpolating in the range a .. b using another factor r (with range 0 .. 1) to indicate the position in that range it's completely unnecessary to determine whether a or b is greater. Either way around you can just use:
result = a + r * (b - a)
If r == 0 this is trivially shown to be a, and if r == 1 the a - a cancels out leaving just b. Similarly if r == 0.5 then the result is (a + b) / 2. It simply doesn't matter if a > b or vice-versa.
The preferred formulation in your case, since it avoids the b - a subtraction that possibly hits range clamping limits is:
result = (1 - r) * a + r * b;
which given appropriate * and + operators on your new RGBA class gives this trivial implementation of your mid function (with no need for per-component operations since they're handled in those operators):
static RGBA mid(const RGBA& a, const RGBA& b, double r) {
return (1.0 - r) * a + r * b;
}
See https://gist.github.com/raybellis/4f69345d8e0c4e83411b, where I've also refactored your RGBA class to put the clamping operations in the constructor rather than within the individual operators.
After some extensive trial-and-error, I finally managed to get it working. (at this point many thanks to #Alnitak, who suggested using a separate RGBA color class.)
The major problem was that, when a color value of the upper constraint was lower than the one of the lower one, I still multiplied with the ratio (x-l)/(u-l), when instead I should have used its pendant, 1 - (x-l)/(u-l), to refer to the color of the upper constraint as the basis for the new one.
Here follows the implementation of the RGBA class and the fixed gradient class:
class RGBA {
private:
unsigned int red = 0, green = 0, blue = 0, alpha = 0;
public:
static RGBA mid(RGBA a, RGBA b, double r) {
RGBA color;
if (a.red < b.red) color.red = a.red + (b.red - a.red) * r;
else color.red = b.red + (a.red - b.red) * (1-r);
if (a.green < b.green) color.green = a.green + (b.green - a.green) * r;
else color.green = b.green + (a.green - b.green) * (1-r);
if (a.blue < b.blue) color.blue = a.blue + (b.blue - a.blue) * r;
else color.blue = b.blue + (a.blue - b.blue) * (1-r);
if (a.alpha < b.alpha) color.alpha = a.alpha + (b.alpha - a.alpha) * r;
else color.alpha = b.alpha + (a.alpha - b.alpha) * (1-r);
return color;
}
RGBA() {};
RGBA(unsigned char _red, unsigned char _green, unsigned char _blue, unsigned char _alpha) :
red(_red), green(_green), blue(_blue), alpha(_alpha) {};
RGBA(unsigned int _rgba) {
red = (_rgba >> 24) & 0xff;
green = (_rgba >> 16) & 0xff;
blue = (_rgba >> 8) & 0xff;
alpha = _rgba & 0xff;
};
operator unsigned int() {
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
RGBA operator+(const RGBA& o) const {
return RGBA((red + o.red) & 0xff, (green + o.green) & 0xff, (blue + o.blue) & 0xff, (alpha + o.alpha) & 0xff);
}
RGBA operator-(const RGBA& o) const {
return RGBA(min(red - o.red, 0u), min(green - o.green, 0u), min(blue - o.blue, 0u), min(alpha - o.alpha, 0u));
}
RGBA operator~() {
return RGBA(0xff - red, 0xff - green, 0xff - blue, 0xff - alpha);
}
RGBA operator*(double _f) {
return RGBA((unsigned int) min(red * _f, 0.) & 0xff, (unsigned int) min(green * _f, 0.) & 0xff,
(unsigned int) min(blue * _f, 0.) & 0xff, (unsigned int) min(alpha * _f, 0.) & 0xff);
}
};
class Gradient {
private:
map<double, RGBA> constraints;
public:
Gradient() {
constraints[0] = RGBA(0x007700ff);
constraints[1] = RGBA(0xffffffff);
}
~Gradient() {}
void addConstraint(RGBA color, double position) {
constraints[position] = color;
}
void reset() {
constraints.clear();
}
unsigned int operator[](double value) {
if (value < 0 || value > 1+1E-10) return 0xff;
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
RGBA lower = lowerC->second;
RGBA upper = upperC->second;
RGBA color = RGBA::mid(lower, upper, (value-lpos)/(upos-lpos));
return color;
}
size_t size() {
return constraints.size();
}
};
This is the result:
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;
DWORD cx = 0xffff00ff;
float cn = .5;
DWORD alphaMask=0xff000000;
DWORD nc = (cx|alphaMask)&((DWORD)(alphaMask*cn)|(~alphaMask));
This should do the trick. all I'm doing here is setting the first 8 bits of the DWORD to 1's with the or (symbolized by '|') and then anding those bits with the correct value you want them to be which is the alpha mask times cn. Of course I casted the result of the multiplication to make it a DWORD again.
This is tested code (in linux). However, you might find a simpler answer. Note: this is RGBA, not ARGB as you have referenced in your question.
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;
}
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;
}
The solution I chose to go with:
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;
}
I understand your question as: I wish to change a given rgba color component by a certain factor while keeping the same overall transparency.
For a color with full alpha (1.0 or 255), this is trivial: simply multiply the component without touching the others:
//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);
There's'probably not a single answer to that question in the general case. Consider that colors may be encoded alternatively in HSL or HSV. You might want to keep some of these parameters fixed, and allow other to change.
My approach to this problem would be to first try to find the hue distance between the source and target colors at full alpha, and then convert the real source color to HSV, apply the change in hue, then convert back to RGBA. Obviously, that second step is not necessary if the alpha is actually 1.0.
In pseudo code:
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;
}
Note how the above rely on type rgba and hsv to have implicit conversion constructors. Algorithms for conversion may be easily found with a web search. It should be also easy to derive struct definitions for hsv from the rgba one, or include individual component access as field members (rather than using the [] operator).
For instance:
//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){}
};
Perhaps you will have to find a hue factor rather than a distance, or tweak other HSV components to achieve the desired result.