3

Background: I have a 32-bit integer with a binary representation like so:

1111 1111 0000 0000 0000 0000 1111 1111

Note: This is the binary representation of the ARGB value of Color.BLUE. I'm using this for illustration purposes, but it is relevant to a situation I am attempting to solve.

The Problem: I am attempting to alter the high order bits so that its binary representation looks like this:

1000 0000 0000 0000 0000 0000 1111 1111

Or more simply, the first eight high order bits should be changed like so:

1111 1111 -> 1000 0000

Current Solution Attempt: Thus far, I've been successful by masking out the first eight high order bits, and then "adding" the desired value using bitwise "or", like so:

int colourBlue = Color.BLUE.getRGB(); // equal to binary value at top of question
int desiredAlpha = (0x80 << 24); // equal to 1000 0000 0000 0000 0000 0000 0000 0000

// Mask out the eight high order bits, and add in the desired alpha value
int alteredAlphaValue = (colourBlue & 0x00FFFFFF) | desiredAlpha;

While this does presently work, admittedly it has been some time since my computer architecture classes, and I have not had a lot of experience yet working with bitwise operators and lower level bit manipulation.

My question: Is my solution the correct way to accomplish this task? If it is in some way improper (or just plain "dumb"), what is a better (or correct) way to achieve the goal of altering specific bits?

Paul Richter
  • 10,908
  • 10
  • 52
  • 85
  • 1
    You know your solution would also wipe out the red and the green parts, if there were any, right? – Dawood ibn Kareem Jan 29 '14 at 00:11
  • Your approach is correct if your bits are arranged as ARGB with 8 bits each. – Steven Hansen Jan 29 '14 at 00:15
  • 2
    @user2864740, your approach wouldn't change the high bits to 0x80 if they were 0x00 to start with. – Steven Hansen Jan 29 '14 at 00:16
  • @DavidWallace Hmm, I just made an attempt with a completely random colour (random RGB values), and it does not appear to change anything other than the highest order bits, as I intended. No code was changed from what I posted. Am I mistaken somewhere? – Paul Richter Jan 29 '14 at 00:16
  • @StevenHansen That's correct, each component is indeed 8 bits each. – Paul Richter Jan 29 '14 at 00:17
  • 4
    @Teeg Your approach is correct. You will not wipe any RGB bits with the mask you specified. – Steven Hansen Jan 29 '14 at 00:18
  • Why are you actually trying to twiddle the bits? what problem are you trying to actually solve with this? – Matt D Jan 29 '14 at 00:55
  • 1
    You've got the general idea. Play with it a little. – Hot Licks Jan 29 '14 at 01:06
  • 1
    Sorry, my mistake. I misread your code. Please ignore my earlier remark. You're doing this exactly the right way. – Dawood ibn Kareem Jan 29 '14 at 01:33
  • @DavidWallace No worries, you forced me to re-examine with a different dataset, which is never bad. – Paul Richter Jan 29 '14 at 03:50
  • @MattD That's a rather large issue on its own. Our application receives tile bitmaps from a geoserver to be placed over top a google map android map. Unfortunately geoserver does not set opacity of the tiles (as far as we can tell); this must be done client-side. Unfortunately, android does not seem to have the usual `BufferedImage`-type classes I would normally use in Java, with the exception of [`Bitmap`](http://developer.android.com/reference/android/graphics/Bitmap.html), which does not do what I need. – Paul Richter Jan 29 '14 at 03:58
  • if the alpha is always 0x80 you can simply use `alteredColor = color & 0x80ffffffff;` – phuclv Jan 22 '15 at 11:46

1 Answers1

2

Transcoded from C# to Java (untested):

public static int setBits(int orig, int newBits, int startBit, int length)
{
    int mask = Mask(startBit, length);
    return (orig & ~mask) | (bits << startBit & mask);
}

public int Mask(int startBit, int length)
{
    if (length ==32)
        return Integer.MAX_VALUE;
    else
        return (1 << (1 << length) - 1) << startbit;
}

Or, if you prefer, you can just specify the mask directly, and avoid the bit-shifting:

public static int setBits(int orig, int newBits, int mask)
{
    return (orig & ~mask) | (bits & mask);

}

Of course, if you're being handed the RGB value as a 32 bit number, you could always convert it to a byte array and vice versa, which makes the manipulations much easier.

Community
  • 1
  • 1
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • If this is going to be done a lot you might improve performance by creating a two-dimensional array of masks up front – Miserable Variable Jan 29 '14 at 00:25
  • Actually, it is unlikely you will improve performance this way in Java. 1) The number of possible masks to precompute could be intractable. 2) The cost of an array fetch in Java includes a bounds check - an extra fetch of the length + 2 comparisons. 3) For a 2-D array, the fetch overheads are (at least) doubled. 4) A large array fetch (with a random index) is going to give you a cache miss, etc. By contrast, bitwise operations are register to register. – Stephen C Jan 29 '14 at 00:55