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]));
Related
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;
}
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 ..
I am trying to convert a byte to integer. All the searches I have done use byte[] which I assume is any array. I want to convert F byte (not b as show below) but it gives error to change: not applicable to the argument.
byte F;
mmInStream.read(packetBytes);
b [counter]= packetBytes[0];
F=b [counter];
counter++;
temp = byteToInt(b); //Convert byte to int
Here is a byte To Int I found on one of the sites.
private int byteToInt(byte[] b) {
int value= 0;
for(int i=0;i<b.length;i++){
int n=(b[i]<0?(int)b[i]+256:(int)b[i])<<(8*i);
value+=n;
}
return value;
}
Simply do:
byte b = ...;
int signedInt = b; // For negative bytes, resulting in negative ints
int unsignedInt = 0xFF & b; // For negative bytes, resulting in positive ints
FYI: An int is 4 bytes. So, that is the reason why the methods you found on the internet are using an array of bytes. They assume you pass an array of 4 bytes, which will be stitched together to make an int.
you can use this:
int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234
or this one also:
public static byte[] intToByteArray(int a)
{
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
and
public static int byteArrayToInt(byte[] b)
{
return (b[3] & 0xFF) + ((b[2] & 0xFF) << 8) + ((b[1] & 0xFF) << 16) + ((b[0] & 0xFF) << 24);
}
if b is unsigned
int i = b & 0xff;
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;
}
Actually I need to transfer the integer value along with the bitmap via bluetooth.. Now my problem is I need to transfer the integer as single byte value..
Is tat possible to convert int as single byte value.. and retrieve it as a integer there... I tried byteValue() and the casting thing but its not usefull.. If my approach is right just help me out with this or say some other way.
(Each time when I am using casting then it's returning as 65535)
What about this?
public static byte[] intToByteArray(int a)
{
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
and
public static int byteArrayToInt(byte[] b)
{
return (b[3] & 0xFF) + ((b[2] & 0xFF) << 8) + ((b[1] & 0xFF) << 16) + ((b[0] & 0xFF) << 24);
}
If you're completely sure, that your int variable contains a byte value [-128; 127] then it should be as simple as:
int i = 100; // your int variable
byte b = (byte) i;
A single byte (8 bits) can only contain 2^8 unsigned integers, i.e [0, 255]. For signed you loose the first bit and the range becomes [-128, 127]. If your integer fits then a simple cast should work.
for 0-255 numbers.
int i = 200; // your int variable
byte b = (byte)(i & 0xFF);