[CODE/JAVA] ARGB_8888 Pixel Abstraction

This is one of the ways you can decode Pixel colors out of the integers you get from Android Pixels.

ARGB_8888, stands for Alpha, Reg, Green, Blue. The 8’s stand for the number of bits per channel.

In Android, signed int‘s are used to represent pixel’s alpha/color information.
Since Android’s language of choice is java, these ints are 32-bit integers, each int takes 4 bytes.

4 bytes = 32 bits = 8bits + 8bits + 8bits + 8bits.

If you had an int like 0xFFAABBCC, each pair of letters on that hexadecimal would mean the following from left to right

{alpha=0xFF}{red=0xAA){green=0xBB}{blue=0xCC}

If you’ve done web programming and played with rgb colors and you didn’t know about this, now it all should click on how your web browser represents colors, except in HTML you don’t deal with the alpha value in the front. On Android’s XML you do.

In bits (binary), the 0xFFAABBCC value would look like this:

    alpha       red         green       blue
    0xFF        0xAA        0xBB        0xCC
    255         170         187         204
{0b11111111}{0b10101010}{0b10111011}{0b11001100}

If you wanted to look at the entire number in binary/bits, it’d be something like this (leaving spaces for visual help):

0b11111111 10101010 10111011 11001100 == 0xFFAABBCC == 4289379276

So if you wanted to get the red channel (0xAA = 170 = 0b10101010) , you’d have to move the whole thing towards the right 16 places, and then compare it with only the rightmost 8 bits.

So, we shift 16 places to the right, we’d get rid of the 2 bytes on the right side and end up only with the left half

0b11111111 10101010

Since we only care about those 8 bits on the right, we do an “&” (bitwise “and”) against 0xFF=255=0b111111111 (all 8 rightmost bits set to 1)

0b11111111 10101010 &
0b00000000 11111111
====================
0b00000000 10101010

So with simple right bit shifting and “& 0xff” of the shifted value we can extract the values per channel.

This class also features a “multiplyByFloat()” function, which I was using to multiply to each channel as I was operating with convolution kernels while playing with image filters.

/** ARGB_8888 Pixel abstraction */
    public static class PixelARGB_8888 {
        public final byte a;
        public final byte r;
        public final byte g;
        public final byte b;
        public final int intVal;

        public PixelARGB_8888(final int argb32bitInt) {
            a = (byte) ((argb32bitInt >> 24) & 0xff);
            r = (byte) ((argb32bitInt >> 16) & 0xff);
            g = (byte) ((argb32bitInt >> 8) & 0xff);
            b = (byte) (argb32bitInt & 0xff);
            intVal = argb32bitInt;
        }

        public PixelARGB_8888(byte a, byte r, byte g, byte b) {
            this.a = a;
            this.r = r;
            this.g = g;
            this.b = b;
            intVal = (a << 24) + (r << 16) + (g << 8) + b;
        }

        public static int multiplyByFloat(float factor, int arg32bitInt) {
            return multiplyByFloat(factor, arg32bitInt, false);
        }

        public static int multiplyByFloat(float factor, 
                                          int argb32bitInt, 
                                          boolean multiplyAlphaChannel) {
            PixelARGB_8888 original = new PixelARGB_8888(argb32bitInt);
            byte alpha = original.a;
            if (multiplyAlphaChannel) {
                alpha = (byte) (original.a * factor);
            }
            PixelARGB_8888 multiplied = new PixelARGB_8888(
                    alpha,
                    (byte) (factor * original.r),
                    (byte) (factor * original.g),
                    (byte) (factor * original.b));
            return multiplied.intVal;
        }
    }

Submit a comment