Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / Visual Basic

ARGB

Rate me:
Please Sign up or sign in to vote.
4.00/5 (17 votes)
15 Jun 2010CPOL4 min read 84.3K   15   10
How ARGB works

Introduction

This article is about how the structure System.Drawing.Color works.

New Color

Take this example:

VB.NET
Dim color1 As New Color 'VB.NET 
C#
Color color1= new Color(); //C#  

When a variable is declared as a color, what happens is:

VB.NET
Shared Sub New()
    Color.Empty = New Color
    Color.StateKnownColorValid = 1
    Color.StateARGBValueValid = 2
    Color.StateValueMask = Color.StateARGBValueValid
    Color.StateNameValid = 8
    Color.NotDefinedValue = 0
End Sub 
C#
static Color()
{
    Empty = new Color();
    StateKnownColorValid = 1;
    StateARGBValueValid = 2;
    StateValueMask = StateARGBValueValid;
    StateNameValid = 8;
    NotDefinedValue = 0L;
} 
MC++
 static Color()
{
    Color::Empty = ();
    Color::StateKnownColorValid = 1;
    Color::StateARGBValueValid = 2;
    Color::StateValueMask = Color::StateARGBValueValid;
    Color::StateNameValid = 8;
    Color::NotDefinedValue = 0;
} 

Empty is a private color declaration which is of not much interest.

StateKnownColorValid is a private Short declaration. This is used in the Color.IsKnownColor (determines if the given color is present in the pre-defined list) property as the AND mask.

StateARGBValueValid is a private Short declaration. This is used in IsKnownColor property, IsNamed property, etc. There are more inaccessible New sub-routines in which this variable is assigned to the variable state used in color-validity checking routines.

StateValueMask has the same uses of StateARGBValueValid.

StateNameValid is used in the Color.ToString function. When we call this function, if that color has a name (like black, etc.), Black is included in the return value. This variable is used as the AND mask in that function to determine if there is a valid name for the color.

NotDefinedValue is used in the Color.FromName function. In that function, if the argument(Object type) is not a valid color, then, the function returns a color. The returned color will have the specification that the color is not defined.

There is an Enumeration called KnownColor. This is the source of all colors. All the color listings in Color are properties.

They look like:

VB.NET
 Public Shared ReadOnly Property AliceBlue As Color
    Get
        Return New Color(KnownColor.AliceBlue)
    End Get
End Property
C#
public static Color AliceBlue
{
    get
    {
        return new Color(KnownColor.AliceBlue);
    }
} 
MC++
public: __property static Color __gc* get_AliceBlue()
{
    return (KnownColor::AliceBlue);
} 

But, in our programming environment, we cannot declare like this. This is because there is another Friend (this keyword specifies that the routine or function or variable can be used only by the assembly in which it is present) declaration of New. The declaration is:

VB.NET
Friend Sub New(ByVal knownColor As KnownColor)
    Me.value = 0
    Me.state = Color.StateKnownColorValid
    Me.name = Nothing
    Me.knownColor = CShort(knownColor)
End Sub
C#
internal Color(KnownColor knownColor)
{
    this.value = 0L;
    this.state = StateKnownColorValid;
    this.name = null;
    this.knownColor = (short) knownColor;
} 
MC++
public private: Color(KnownColor __gc* knownColor)
{
    this->value = 0;
    this->state = Color::StateKnownColorValid;
    this->name = 0;
    this->knownColor = *static_cast<__box Int16*>(knownColor);
} 

The primary use of this is in returning a color like Color.AliceBlue. This is merely to shorten the code. Writing 4 lines for each and every color is time consuming and increases the size of the assembly. So, this practice is implemented.

There is one last Private declaration of New. The source code for it is:

VB.NET
Private Sub New(ByVal value As Long, ByVal state As Short, _
	ByVal name As String, ByVal knownColor As KnownColor)
    Me.value = value
    Me.state = state
    Me.name = name
    Me.knownColor = CShort(knownColor)
End Sub
C#
private Color(long value, short state, string name, KnownColor knownColor)
{
    this.value = value;
    this.state = state;
    this.name = name;
    this.knownColor = (short) knownColor;
} 
MC++
private: Color(Int64 __gc* value, Int16 __gc* state, String __gc* name, 
	KnownColor __gc* knownColor)
{
    this->value = value;
    this->state = state;
    this->name = name;
    this->knownColor = *static_cast<__box Int16*>(knownColor);
} 

This is a Private declaration first of all because the values are directly assigned without any error checking. The main source of error could be the first long argument value. This argument is the ARGB value that is stored in the internal variable value in Color. Since retrieving the Alpha, Red, Green and Blue components of a color from value involves bitwise operations (I will be telling about this soon) - machine-level operations which are intimidating to beginners.

This declaration of New is used in the FromARGB function and the FromName function.

ARGB - Alpha Red Green Blue

What is ARGB?

ARGB is nothing but transparency added to the standard RGB color composition. Alpha can range from 0 to 255 like the Red, Green and Blue components.

How Is It Stored

Instead of wasting 4 byte data types (sums up to 32 bits), ARGB values are stored using one single long data type or a 32 bit integer for efficiency purposes. Operating on 1 variable is way easier than performing operations on 4 different variables. This is just like the way DOS and few versions of Windows stored the date on which a file was created/modified in a single variable (2-byte entry).

Every component is allowed 8 bits because the highest value they can have is 255 and 255 in binary is 11111111.

In earlier versions like VB6, we could create a color using a function called RGB and it is still supported in the .NET versions.

But, the .NET programming languages use ARGB for all colors.

This is how we can make our own color:

VB.NET
Color.FromArgb(alpha, red, green, blue) 'VB.NET. All variables can range from 0-255
C#
Color.FromArgb(alpha, red, green, blue); //C#. All variables can range from 0-255
MC++
Color::FromArgb(alpha, red, green, blue); //C++/CLI. All variables can range from 0-255

The code for this FromArgb function is as follows:

VB.NET
 Public Shared Function FromArgb(ByVal alpha As Integer, _
	ByVal red As Integer, ByVal green As Integer, ByVal blue As Integer) As Color
    Color.CheckByte(alpha, "alpha")
    Color.CheckByte(red, "red")
    Color.CheckByte(green, "green")
    Color.CheckByte(blue, "blue")
    Return New Color(Color.MakeArgb(CByte(alpha), _
	CByte(red), CByte(green), CByte(blue)), Color.StateARGBValueValid, _
	Nothing, DirectCast(0, KnownColor))
End Function
C#
public static Color FromArgb(int alpha, int red, int green, int blue)
{
    CheckByte(alpha, "alpha");
    CheckByte(red, "red");
    CheckByte(green, "green");
    CheckByte(blue, "blue");
    return new Color(MakeArgb((byte) alpha, (byte) red, (byte) green, 
	(byte) blue), StateARGBValueValid, null, (KnownColor) 0);
}
MC++
public: static Color __gc* FromArgb(Int32 __gc* alpha, 
	Int32 __gc* red, Int32 __gc* green, Int32 __gc* blue)
{
    Color::CheckByte(alpha, S"alpha");
    Color::CheckByte(red, S"red");
    Color::CheckByte(green, S"green");
    Color::CheckByte(blue, S"blue");
    return (Color::MakeArgb(*static_cast<__box Byte*>(alpha), 
	*static_cast<__box Byte*>(red), *static_cast<__box Byte*>(green), 
	*static_cast<__box Byte*>(blue)), Color::StateARGBValueValid, 0, 
	*static_cast<__box KnownColor*>(0));
}

First, the function checks if all the arguments alpha, red, blue and green have valid values(0-255). This is what the CheckByte function does.

Color.MakeArgb function is the function that converts the separate components into one single 32-bit Integer or Long. Its source code is:

VB.NET
Private Shared Function MakeArgb(ByVal alpha As Byte, _
	ByVal red As Byte, ByVal green As Byte, ByVal blue As Byte) As Long
    Return CLng((CULng(((((red << &H10) Or (green << 8)) Or blue) _
	Or (alpha << &H18))) And &HFFFFFFFF))
End Function
C#
private static long MakeArgb(byte alpha, byte red, byte green, byte blue)
{
    return (long) (((ulong) ((((red << 0x10) | (green << 8)) 
		| blue) | (alpha << 0x18))) & 0xffffffffL);
}
MC++
private: static Int64 __gc* MakeArgb(Byte __gc* alpha, 
Byte __gc* red, Byte __gc* green, Byte __gc* blue)
{
    return *static_cast<__box Int64*>((*static_cast<__box UInt64*>
	(((((red << 0x10) | (green << 8)) | blue) | (alpha << 0x18))) & 0xffffffff));
} 

If you don't know what Bit-wise operators are or if you have some problems regarding them, read this article on CodeProject - an excellent place to start with.

First, we need to convert the hexadecimal numbers &H10 etc. and octal numbers like 0x10, etc. to human-readable decimal form.

Then, the statements will be:

VB.NET
CLng((CULng(((((red << 16) Or (green << 8)) Or blue) _
   Or (alpha << 24))) And 4294967295))
C#
(long) (((ulong) ((((red << 16) | (green << 8)) | blue) | 
	(alpha << 24))) & 4294967295L)) 
C#
*static_cast<__box Int64*>((*static_cast<__box UInt64*>(((((red << 16) | 
	(green << 8)) | blue) | (alpha << 24))) & 4294967295)

Let us analyze this expression. I will take the C# expression for analyzing.

C#
((((red << 16) | (green << 8))  | blue)  | (alpha << 24)) & 4294967295
  1. red is left shifted 16 bits.
  2. green is left shifted 8 bits.
  3. Both the results are OR-ed.
  4. The OR-ed result is again OR-ed by blue
  5. alpha is left shifted 24 bits.
  6. Then it is OR-ed with the result in (4).
  7. The result in (6) is AND-ed with 4294967295

Let us take an example to understand it better.

Color : Gold

Alpha : 255 (11111111)

Red   : 255 (11111111)

Green : 215 (11010111)

Blue :  0   (00000000)


Red << 16 : 

16711680

111111110000000000000000

Green << 8 : 

55040

1101011100000000

(Red << 16) | (Green << 8) : 

11111111 00000000 00000000 (Red's value shifted to first 8 bits)

00000000 11010111 00000000 (Green's value shifted to second 8 bits)
_________________________

11111111 11010111 00000000 (OR-ed result)

Notice that the first eight bits are occupied by red and
the second eight bits are occupied by green.

((Red << 16) | (Green << 8))|Blue : 

11111111 11010111 00000000 (The last 8 bits are for Blue)

00000000 000000000 0000000 (The last 8 bits are Blue. In this case, 0)
_________________________

11111111 11010111 00000000 (These 3 values are Red, Blue and Green)

Alpha << 24 : 

4278190080

11111111000000000000000000000000

(((Red << 16) | (Green << 8))|Blue) | Alpha << 24 : 

00000000 11111111 11010111 00000000 (24-bit to 32-bit leaving the first 8 bits for Alpha)

11111111 00000000 00000000 00000000 (First 8 Bits have the value)
__________________________________

11111111 11111111 11010111 00000000 (Alpha, Red, Green, Blue)

((((Red << 16) | (Green << 8))|Blue) | Alpha << 24) & 4294967295 : 

    11111111 11111111 11010111 00000000

    11111111 11111111 11111111 11111111 (256^4)
    ___________________________________

    11111111 11111111 11010111 00000000

       |         |       |         |

      ALPHA     RED    GREEN      BLUE 
BITS  32-24   24-16    16-8       8-0

Finally, we AND by 256^4 because there are 4 values with range 0-255(256 values)

Note: This isn't the value returned by Color.ToArgb() function because it returns an Integer value which is a conversion of a Long value. Since the limit exceeds, a negative value is returned.

Retrieving the Components from an ARGB Value

ALPHA

VB.NET
 Public ReadOnly Property A As Byte
    Get
        Return CByte(((Me.Value >> &H18) And &HFF)) '&H18 is 24, &HFF is 255
    End Get
End Property
C#
public byte A
{
    get
    {
        return (byte) ((this.Value >> 0x18) & 0xffL); // 0x18 is 24, 0xff is 255
    }
}
MC++
public: __property Byte __gc* get_A()
{
    return *static_cast<__box Byte*>(((this->Value >> 0x18) & 0xff));
} 

value is right shifted 24 bits and is AND-ed with 255 to get the Alpha.

11111111 11111111 11010111 00000000 >> 24 = 00000000 00000000  00000000 11111111

00000000 00000000  00000000 11111111 & 255 = 11111111 = 255 

The same explanation applies to the following.

RED

VB.NET
Public ReadOnly Property R As Byte
    Get
        Return CByte(((Me.Value >> &H10) And &HFF))
    End Get
End Property
C#
public byte R
{
    get
    {
        return (byte) ((this.Value >> 0x10) & 0xffL);
    }
}
MC++
public: __property Byte __gc* get_R()
{
    return *static_cast<__box Byte*>(((this->Value >> 0x10) & 0xff));
}
Red = value >> 16 & 255

BLUE

VB.NET
Public ReadOnly Property B As Byte
    Get
        Return CByte((Me.Value And &HFF))
    End Get
End Property
C#
 public byte B
{
    get
    {
        return (byte) (this.Value & 0xffL);
    }
} 
MC++
public: __property Byte __gc* get_B()
{
    return *static_cast<__box Byte*>((this->Value & 0xff));
}

Since blue wasn't shifted, AND-ing it with 255 will give blue.

blue = value & 255

GREEN

VB.NET
Public ReadOnly Property G As Byte
    Get
        Return CByte(((Me.Value >> 8) And &HFF))
    End Get
End Property
C#
public byte G
{
    get
    {
        return (byte) ((this.Value >> 8) & 0xffL);
    }
}
MC++
public: __property Byte __gc* get_G()
{
    return *static_cast<__box Byte*>(((this->Value >> 8) & 0xff));
}
green = value >> 8 & 255

That is all!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Student
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
bluedog says29-Jun-10 15:23
bluedog says29-Jun-10 15:23 
RantMy vote of ... the vote could be normalized Pin
riccardo6821-Jun-10 23:58
professionalriccardo6821-Jun-10 23:58 
GeneralRe: My vote of ... the vote could be normalized Pin
Anshul R22-Jun-10 0:50
Anshul R22-Jun-10 0:50 
GeneralMy vote of 1 Pin
chad_ross17-Jun-10 16:30
chad_ross17-Jun-10 16:30 
No real application for articles subject
Question[My vote of 2] Is this really useful ? Pin
Maximilien16-Jun-10 3:07
Maximilien16-Jun-10 3:07 
AnswerRe: [My vote of 2] Is this really useful ? Pin
Anshul R16-Jun-10 3:08
Anshul R16-Jun-10 3:08 
GeneralMy vote of 2 Pin
johannesnestler15-Jun-10 22:38
johannesnestler15-Jun-10 22:38 
GeneralMy vote of 1 Pin
goorley15-Jun-10 21:53
goorley15-Jun-10 21:53 
GeneralRe: My vote of 1 Pin
Anshul R15-Jun-10 22:29
Anshul R15-Jun-10 22:29 
GeneralRe: My vote of 1 Pin
Ajay Vijayvargiya16-Jun-10 7:15
Ajay Vijayvargiya16-Jun-10 7:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.