How to convert RGB to BGR? - java

This is probably easy, but I'm trying to convert from a source which provides colors in RGB strings to an output in BGR strings in Java. I've been busting my brain and time on shifting and Long.decode and Long.toHexString.
Feel free to also throw alpha values in there (RGBA -> ABGR), though I think I can extend the principles.
I can assume that the hex is in the form specified in the long and int decode:
0x HexDigits
0X HexDigits
# HexDigits

For 24bit colors (8 bits to each of R,G,B):
String rgbSource = getRGBSource(); //your function to get a string version of it
int in = Integer.decode(rgbSource);
int red = (in >> 16) & 0xFF;
int green = (in >> 8) & 0xFF;
int blue = (in >> 0) & 0xFF;
int out = (blue << 16) | (green << 8) | (red << 0);

int abgr = Integer.reverseBytes(rgba);
Including supporting code, with the assumption that it is safe to decide whether alpha needs adding based on the string length (consider "0xFFFFFF".length() for example):
String rgb = getRGB();
//decodes a number of hex formats and sets alpha
int rgba = rgb.length() < 8 ?
Long.decode(rgb + "ff").intValue() :
Long.decode(rgb ).intValue();
int abgr = Integer.reverseBytes(rgba);
Here's a one line method:
public static String reverseRGB(String rgba) {
return String.format("%08X",Integer.reverseBytes(Long.decode(rgba.length() < 8 ? rgba + "ff" : rgba).intValue()));
}

If the input is a 6 character rgb string:
String bgr = rgb.substring(4,6) + rgb.substring(2,4) + rgb.substring(0,2);
If the input is an 8 character rgba string:
String abgr = rgba.substring(6,8) + rgba.substring(4,6) + rgba.substring(2,4) + rgba.substring(0,2);
If the input is an int with 8 bit channels:
String bgr = String.format( "%02X%02X%02X" , rgb & 0x00FF , (rgb>>8) & 0x00FF , (rgb>>16) & 0x00FF );
String abgr = String.format( "%02X%02X%02X%02X" , rgba & 0x00FF , (rgba>>8) & 0x00FF , (rgba>>16) & 0x00FF , (rgba>>24) & 0x00FF );
// or
String bgr = String.format( "%06X" , Integer.reverseBytes( rgb ) >> 8 );
String abgr = String.format( "%08X" , Integer.reverseBytes( rgba ) );

Here is how I got it to work, but I really hope there is a better way because this is awful. Please come up with a cleaner, more efficient way to do this, so I can give you rep.
long number = (rgb.length() < 8 ? Long.decode(rgb+ "ff") : Long.decode(rgb)); //decodes a number of hex formats and sets alpha
String abgrColor = (new StringBuilder())
.append((Long.toHexString((number) & 0xFF).length()==2? Long.toHexString((number) & 0xFF): "0"+Long.toHexString((number) & 0xFF)))
.append((Long.toHexString((number>>8) & 0xFF).length()==2? Long.toHexString((number>>8) & 0xFF): "0"+Long.toHexString((number>>8) & 0xFF)))
.append((Long.toHexString((number>>16) & 0xFF).length()==2? Long.toHexString((number>>16) & 0xFF): "0"+Long.toHexString((number>>16) & 0xFF)))
.append((Long.toHexString((number>>24) & 0xFF).length()==2? Long.toHexString((number>>24) & 0xFF): "0"+Long.toHexString((number>>24) & 0xFF)))
.toString();

This should work.
public static int swapByte1And3(int inValue) {
int swap = inValue & 0xFF;
swap = swap << 16 | (inValue >>> 16 & 0xFF);
return inValue & 0xFF00FF00 | swap;
}
public static int convertBRGtoRBG(int inColor) {
return swapByte1And3(inColor);
}
public static int convertABRGtoRBGA(int inColor) {
int swap = inColor >>> 24;
inColor = convertBRGtoRBG(inColor) << 8;
return inColor | swap;
}

Related

Java byte Array to signed Int

I'm trying to convert a signed int variable to a 3 byte array and backwards.
In the the function getColorint, I'm converting the int value to the byte array. That works fine!
public byte [] getColorByte(int color1){
byte[] color = new byte[3];
color[2] = (byte) (color1 & 0xFF);
color[1] = (byte) ((color1 >> 8) & 0xFF);
color[0] = (byte) ((color1 >> 16) & 0xFF);
return color;
}
But if I try to convert the byte array back to the Integer with the getColorint function:
public int getColorint(byte [] color){
int answer = color [2];
answer += color [1] << 8;
answer += color [0] << 16;
return answer;
}
it only works for positive integer values.
Here is a screenshot during the debug:
My input int value is -16673281 but my output int value is 38143.
Can anyone help me?
Thanks :)
The Color class defines methods for creating and converting color ints. Colors are represented as packed ints, made up of 4 bytes: alpha, red, green, blue.
You should use it.
The problem here is that byte is signed. When you do int answer = color[2] with color[2] == -1, then answer will be also -1, i.e. 0xffffffff, whereas you want it to be 255 (0xff). You can use Guava 's UnsignedBytes as a remedy, or simply take color[i] & 0xff which casts it to int.
As is Color represents in 4 bytes, you should store also an alpha channel.
From Int :
public byte [] getColorByte(int color1){
byte[] color = new byte[4];
for (int i = 0; i < 4; i++) {
color [i] = (byte)(color1 >>> (i * 8));
}
return color;
}
To Int :
public int getColorInt(byte [] color){
int res = ((color[0] & 0xff) << 24) | ((color[1] & 0xff) << 16) |
((color[2] & 0xff) << 8) | (color[3] & 0xff);
return res;
}

Java: custom to byte conversions

I am working with some low capacity module and I need to compress the data as much as possible. The data will look like this:
DeviceEvent:
1 byte:
2 bits for status (00 each time)
6 bits for rgb color (3 x 2 bits)
2 bytes: number of minutes from now to a certain datetime
I need to create a constructor (preferably 2 constructors) for conversion from/to:
Event:
byte[] color (rgb, colors will get simplified to only 64 available)
some datetime (but I will get the integer for difference in minutes and it will be small enough to fit in two bits)
So basically I need:
byte[3] color <-> 1 byte status and color
int minutes <-> byte[2]
minutes
I will be thankful for any help
I'm not very sure what is your problem, probably this will help:
final byte red = 1; // 01 binary
final byte green = 2; // 10 binary
final byte blue = 3; // 11 binary
final byte finalColor = (byte) ((red & 0x3) << 4) | ((green & 0x3) << 2) | (blue & 0x3);
System.out.println(finalColor);// finalColor is 011011 = 27 decimal
final int minutes = 0x1234; // first byte is 0x12, second byte is 0x34
final byte[] bytes = {(byte) (((minutes) >>> 8) & 0xff), (byte) (minutes & 0xff)};
System.out.println(bytes[0]); // 0x12 = 18 decimal
System.out.println(bytes[1]); // 0x34 = 52 decimal
I am not sure what the second problem is. So I made these two functions that might help you:
public static int convertToInt(int a, int b, int c, int d) {
a = Math.min(a, 255);
b = Math.min(b, 255);
c = Math.min(c, 255);
d = Math.min(d, 255);
return ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF);
}
public static int[] extractComponents(int data) {
int a = (data >> 24) & 0xFF;
int b = (data >> 16) & 0xFF;
int c = (data >> 8) & 0xFF;
int d = data & 0xFF;
return new int[] {a, b, c, d};
}
The convertToInt function takes four numbers(that are less than 255) and puts them all in one int.
The extractComponents function does the opposite.
This is an example:
int data = 0xC8E0601B;
int[] dataA = extractComponents(data);
for(int i = 0 ; i < dataA.length; i++) System.out.printf("%x\n", dataA[i]);
System.out.printf("%x\n", convertToInt(dataA[0], dataA[1], dataA[2], dataA[3]));

How to convert number to argb value?

How can you convert a number into an argb value such that
0 -> 0,0,0,0
1 -> 0,0,0,1
...
(16^8)-1 -> 255,255,255,255
and vice versa so
0,0,0,0 -> 0
0,0,0,1 -> 1
...
255,255,255,255 -> (16^8)-1
Thanks
As additional solution to the answer above, given the sample code below, the result of (16^8)-1 is 23. Which you would like to be of color white. Is there any special reason to do this? Refering to Color
This is what you want to do:
int argb = (16 ^ 8) - 1; //Result is 23 any reason for this?
If we use the same color conversion of Color object.
Color c = Color.FromArgb(255, 255, 255, 255);
c.ToArgb(); //We get -1
Which we will get on the same result with this solution:
int v = (c.A << 24) + (c.R << 16) + (c.G << 8) + c.B; //Result is -1
Revert it back:
int a = (v >> 24) & 0xFF;
int r = (v >> 16) & 0xFF;
int g = (v >> 8) & 0xFF;
int b = (v) & 0xFF;
Try to check the above reference (and experiment) if this will fit your need.
Completely ignoring system methods, you can implement a custom method to do what you ask in C# like the following:
public static long argbToLong(int a, int r, int g, int b)
{
new[] { a, r, g, b }.Select((v, i) => new { Name = "argb"[i].ToString(), Value = v }).ToList()
.ForEach(arg =>
{
if (arg.Value > 255 || arg.Value < 0)
throw new ArgumentOutOfRangeException(arg.Name, arg.Name + " must be between or equal to 0-255");
});
long al = (a << 24) & 0xFF000000;
long rl = (r << 16) & 0x00FF0000;
long gl = (g << 8) & 0x0000FF00;
long bl = b & 0x000000FF;
return al | rl | gl | bl;
}
public static Tuple<int, int, int, int> longToArgb(long argb)
{
var max = Math.Pow(16, 8) - 1;
if (argb < 0 || argb > max)
throw new ArgumentOutOfRangeException("argb", "argb must be between or equal to 0-" + max);
int a = (int)((argb & 0xFF000000) >> 24);
int r = (int)((argb & 0x00FF0000) >> 16);
int g = (int)((argb & 0x0000FF00) >> 8);
int b = (int)(argb & 0x000000FF);
return new Tuple<int, int, int, int>(a, r, g, b);
}
Wasn't sure what language, since C# and Java is tagged.
You can use bitwise operators with 8 bits offset. For example, in RGB 255,255,128 to integer would be (255 << 16) + (255 << 8) + (128)
If you need another octet just add it with << 24.. Like (a << 24) + (r << 16) + (g << 8) + b ..

Fast algorithm to invert an ARGB color value to ABGR?

I'm using IntBuffer to manipulate pixels of a Bitmap, but the value in the buffer should be AABBGGRR, while the color constants are AARRGGBB. I know I can use Color.argb, Color.a, ... to invert, but I think it's not perfect.
I need to manipulate a very large number of pixels, so I need an algorithm that can perform this operator in short time. I think of this Bit Expression, but it's not correct:
0xFFFFFFFF ^ pSourceColor
If there's no better one, maybe I will use bit-shift operators (that performs Color.a, ...) instead of calling the functions to reduce the time.
EDIT:
This is my current function to convert, though I think there shoul be a better algorithm (less operators) to perform it:
private int getBufferedColor(final int pSourceColor) {
return
((pSourceColor >> 24) << 24) | // Alpha
((pSourceColor >> 16) & 0xFF) | // Red -> Blue
((pSourceColor >> 8) & 0xFF) << 8 | // Green
((pSourceColor) & 0xFF) << 16; // Blue -> Red
}
Since A and G are in place, you can probably do a little better by masking off the B and R and then adding them back. Haven't tested it but ought to be 95% right:
private static final int EXCEPT_R_MASK = 0xFF00FFFF;
private static final int ONLY_R_MASK = ~EXCEPT_R_MASK;
private static final int EXCEPT_B_MASK = 0xFFFFFF00;
private static final int ONLY_B_MASK = ~EXCEPT_B_MASK;
private int getBufferedColor(final int pSourceColor) {
int r = (pSourceColor & ONLY_R_MASK) >> 16;
int b = pSourceColor & ONLY_B_MASK;
return
(pSourceColor & EXCEPT_R_MASK & EXCEPT_B_MASK) | (b << 16) | r;
}
In my opinion, the following function is fast enough to return the ABGR color while passing an ARGB color and vice-versa!
int argbToABGR(int argbColor) {
int r = (argbColor >> 16) & 0xFF;
int b = argbColor & 0xFF;
return (argbColor & 0xFF00FF00) | (b << 16) | r;
}

Java bit operations error (convert to byte and convert back)

I'm trying to convert date of birth (three ints) to byte and convert it back but I'm having an issue. I have to convert it by using bit operations and send data over multicast server and receive it and change back to int. Server works fine, but bit operations are hard for me. What's the matter with the code:
Convert:
int D=12;
int M=9;
int Y=1983;
short DMY=0;
DMY = (short)(DMY | (D << 19));
DMY = (short)(DMY | (M << 15));
DMY = (short)(DMY | Y);
byte[] data = new byte[3];
data[0] = (byte)(DMY >>> 8 );
data[1] = (byte)(DMY >>> 16 );
data[2] = (byte)(DMY & 0xffff);
Convert back:
byte[] rec_data = new byte[3];
rec_data = dp.getData();
short Rec_dmy;
Rec_dmy = (short)(rec_data[0] & 0xff);
Rec_dmy = (short) (Rec_dmy << 8);
Rec_dmy = (short)(Rec_dmy | (rec_data[1] & 0xff));
Rec_dmy = (short) (Rec_dmy << 8);
Rec_dmy = (short)(Rec_dmy | (rec_data[2] & 0xffff));
byte tmp = (byte) ((Rec_dmy >>> 19) & 0x1F);
byte tmp2 = (byte) ((Rec_dmy >>> 15) & 0x1FF);
byte tmp3 = (byte) (Rec_dmy & 0x7F);
System.out.println(tmp);
System.out.println(tmp2);
System.out.println(tmp3);
Println gives following answer:
31
-1
63
It's not near original 12 9 1983
Shorts can only hold 16 bits; you are trying to pack more than that (e.g. shifting day left by 19, which will result in an all-zero value once casted to a short). You need to use an int or a long to hold all the fields.
Indeed, you've got several things going on with the bit operations that aren't right.
My suggestion would be to ditch the bit operations and just send the day, month and year as separate fields: one byte for each of the day and month, and two (a short) for the year. That takes 4 bytes (only one extra byte) but requires a lot less fiddling to get right.
Its not easy, but you have to work systematically to ensure your operations don't a) lose information b) decode the reverse of how you have encoded.
int D = 12;
int M = 9;
int Y = 1983;
int DMY = (D << 19) | (M << 15) | Y;
byte[] data = new byte[3];
data[0] = (byte) (DMY >>> 16);
data[1] = (byte) (DMY >>> 8);
data[2] = (byte) DMY;
int DMY2 = ((data[0]&0xFF) << 16) | ((data[1]&0xFF) << 8) | (data[2]&0xFF);
int D2 = DMY2 >>> 19; // no mask required
int M2 = (DMY2 >>> 15) & 0x0F; // 4 bits mask
int Y2 = DMY2 & 0x7FFF; // 15 bit mask
System.out.println(D2 + "/" + M2 + "/" + Y2);
prints
12/9/1983
First, you need at least 14 bits to represent the year with max value 9999 because of 2^14 > 9999 && 2 ^ 13 < 9999. And the least number of bits for month is 4(12 at max), day is 5(31 at max). So you can use a short int(16 bits) to represent year and byte (8 bits) for each day and month. So you get a 32-bits int.
public int encoded(short year, byte month, byte day){
int data =0;
data = year & 0xFFFF;
data =(data << 8)|(month & 0xFF)
data =(data << 8)|(day & 0xFF)
return data;
}
public void decode(int data){
int day = data & 0xFF;
int month = (data >> 8) & 0xFF;
int year = (data >> 16) & 0xFFFF;
}

Categories

Resources