The right way to pack BGRA and ARGB color to int

0

In SharpDx BGRA shift for red is 16:

(color >> 16) & 255

see here.

But in .NET, ARGB shift for red is also 16:

private const int ARGBRedShift = 16;

see here and here and here.

I'm confused, what's right?

this (like .NET):

public int PackeColorToArgb()
{
    int value = B;
    value |= G << 8;
    value |= R << 16;
    value |= A << 24;

    return (int)value;
}

or this (like SharpDx):

public int PackeColorToArgb()
{
    int value = A;
    value |= B << 8;
    value |= G << 16;
    value |= R << 24;

    return (int)value;
}

For .Net 0xFFFF0000 is Argb Red, but for SharpDx this is Bgra Red. what's right?

c#
.net
colors
sharpdx
argb
asked on Stack Overflow Sep 25, 2019 by google dev • edited Sep 26, 2019 by Peter Duniho

1 Answer

1

The right way to pack BGRA and ARGB color to int

That depends on where you're going to use the int. But for the two examples you've provided, you'll pack the byte values into the integer value in exactly the same way. They are both "right". It's only the name that's different, and you can have many different names for the same thing.

Importantly, your second code example — supposedly "correct" for SharpDx — is not correct for the color format you're asking about. You can see right in the source code you reference, while you are packing the bytes in the order A, B, G, and R, LSB to MSB, the correct order of component is in fact BGRA (again, LSB to MSB).

Your second code example should look just like the first.

Long version…

As you can see from the two source code references you've noted, the actual formats are identical. That is, the format from each API, stores the byte values for each color component in the same order, within a single 32-bit integer: blue in the lowest 8 bits, then green, then red, then alpha in the highest 8 bits.

The problem is, there's no uniform standard for naming such formats. In the context of .NET, they list the color components in big-endian order (which could be thought of as a little ironic, since so much of the Windows ecosystem is based on little-endian hardware…but, see below). I.e. the most-significant byte is listed first: "ARGB". I call this name "big-endian order" simply because that name is consistent with a scenario in which one stores the 32-bit integer in a sequence of 4 bytes in memory on a computer running in big-endian mode. The order of component initials in the name is the same order they'd appear in that context.

On the other hand, in the context of SharpDx, the name is consistent with the order of bytes you'd see on little-endian hardware. The blue byte would come first in memory, then green, red, and finally alpha.

Fact is, both of these are somewhat arbitrary. While most mainstream PCs are running in little-endian mode now, which would argue in favor of the SharpDx naming scheme (which is inherited from the DirectX environment), these APIs both also can be found on big-endian hardware as well, especially as .NET Core is gaining traction. And in a lot of cases, the programmer using the API doesn't even really care what order the bytes are in. For code that has to deal with the individual bytes, it's still important, but a lot of the time it's more about just knowing what format the tools you're using is writing bitmaps in, and then making sure you've specified the correct format to the API.

All that said, I suspect that the main reason for the discrepancy has less to do with big-endian vs little-endian and more to do with underlying philosophical differences between the people responsible for the API. The fact is, even on big-endian hardware, the SharpDx format for a pixel where the components show up in memory in BGRA order will be "BGRA". Because, bitmap formats don't change just because the byte-order mode of the hardware is different. A pixel is not an integer. It's just a sequence of bytes. What will be different is that the shift values will have to be different, i.e. reversed, so that for code that does treat the pixel as a single 32-bit integer, it can access the individual components correctly.

Instead, it seems to me that the .NET designers recognized that the users of their API will most of the time be dealing with colors at a high level (e.g. setting the color of a pen or brush), not at the pixel level of bitmaps, and so naming the pixel format according to conventional order makes more sense. On the other hand, in SharpDx people are much more often dealing with the low-level pixel data, and having a name that reflects the actual byte-wise sequence of components for a pixel makes more sense in that context.

Indeed, the .NET code you've referenced doesn't involve bitmap data. The Color struct is only ever dealing with single int values at a time, with respect to the "ARGB" nomenclature. Since conceptually, we imagine numbers in big-endian format (even for decimal, i.e. with the most-significant digits first), ARGB is more human-readable. On the other hand, in the areas of .NET that do involve byte order in pixel formats, you'll find that the naming goes back to being representative of the actual byte order, e.g. the list of PixelFormats introduced with WPF.

Clear as mud, right? :)

answered on Stack Overflow Sep 26, 2019 by Peter Duniho • edited Sep 26, 2019 by Peter Duniho

User contributions licensed under CC BY-SA 3.0