All related questions I've found here on SO describe the conversion between a byte array and an int array where 4 bytes are converted to a single integer and vice versa.
What I am looking for instead is converting each integer to a single byte and vice versa, knowing that none of the values of the integer array exceeds the range of an unsigned byte.
Is there a library that does that (preferably Guava or Apache commons)? Essentially, I am looking for something like this:
int[] -> byte[]
for (int i = 0; i < intArray.length; i++){
byteArray[i] = (byte) intArray[i];
}
byte[] -> int[]
for (int i = 0; i < byteArray.length; i++){
intArray[i] = 0xff & byteArray[i];
}
You cannot cast arrays in Java in that way. AFAIK, the VM just does not let you reinterpret the bytes in an array as a different type. I assume that you could use some platform-dependent JNI magic to make it so, but that would be extremely hacky.
Edit (removed sample code; added following)
If you are going to reinterpret the same bytes as different primitive types, use a ByteBuffer.
Once declared, you get direct access operations to reinterpreted bytes, such as
myByteBuffer.getInt(1); // reads bytes 4, 5, 6, 7 as an int
myByteBuffer.getByte(5); // reads byte 5 as a byte
You can also extract primitive arrays from there, but there will be extra allocations involved.
Try:
int number = 54353, divisor = 256;
byte[] byteArray = new byte[4];
byteArray[3] = number%divisor;
number = number/divisor
byteArray[2] = number%divisor;
number = number/divisor
byteArray[1] = number%divisor;
number = number/divisor
byteArray[0] = number;
Related
I need to convert integers that I send over 4bytes per socket in java. The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
I read in the instructions this line:
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
The problem is that I don't know how to write the appropriate conversion function. Here is the one I had implemented and which seems to work for integers from 0 to 9. Can someone help me.
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
ByteBuffer has nice functionality for this:
byte[] bytes = new byte[4];
ByteBuffer.wrap(bytes)
.order(ByteOrder.BIG_ENDIAN) // make explicit
.putInt(intValue);
// bytes is now updated
ByteBuffer Doc in java SE 8
I need to convert integers that I send over 4bytes per socket in java.
Probably no actual conversion is required.
The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
Nothing in what you have presented suggests why that would be, though in fact the conversion presented is wrong.
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
This is Java's native representation for type int. You can write ints to the socket's output stream by wrapping it in a DataOutputStream and using DataOutputStream.writeInt(). Or if you are using NIO then you can put an int into a ByteBuffer via the buffer's putInt() method. Either of these approaches sidesteps any need to manually encode integers into byte arrays.
But if you insist on doing your own conversion, completely manually, then this ...
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
... reads out the bytes in little-endian order instead of big-endian (most-significant to least). This would be a correct alternative:
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> ((3 - i) * 8));
}
You state you tried +Inf, but that is not an int value. The only number type you can stick +Inf into is double or float, but it's a compiler error to attempt to do >>> to a double or float.
Also, the code snippet you wrote doesn't work for anything - it turns things into little endian order. It treats 9 the exact same way it treats 10: 9 turns into [9, 0, 0, 0] (which is 9 in 2's complement int, but, little endian), and 10 becomes [10, 0, 0, 0].
In other words, you've either thoroughly misanalysed your own code, or you aren't running that snippet.
This will work fine:
int n = -2;
byte[] sizeBuffer = new byte[4];
for (int i = 0; i < 4; i++) {
sizeBuffer[i] = (byte)(n >>> (24 - (i * 8)));
}
Turns -1 into [255, 255, 255, 254] (in java bytes are rendered signed, so if you try to print that, it'll probably show as -1, -1, -1, -2. It's the same thing) - and that is indeed -2 in 2's complement big endian.
You can make a ByteBuffer and write that way as well.
I have a Byte array being returned in my JSON.
JSON
[{"template":167,255,1,30,179,0,218,0,2,88,1,184,0],
"template2":null,
"template3":null,
"Client_Id":1160739}]
In Java, how can I recover this byte array ?
I try return a String in JSON instead the byte array, but when I convert to byte, it will change the value that I need. Example, 167 is the value that I need because this is already the byte value, but if I try to convert 167 to byte, it will return another value, so I need recover it as byte value.
JAVA
ArrayList<JSONObject> vetor = ArrayJson(client);
byte[] template = (byte[])vetor.get(0).get("template");
I'm using the json.org/java repository to construct the json helper class.
The byte data type is good for 256 different numbers - yet, in java, when you use bytes, they are interpreted as signed two's complement numbers. This is most likely what happens to you. Note that the bit pattern is not changed, only the output changes.
You can recover the unsigned value in byte b with (b & 0xff)
JSON has no concept of bytes, so what you have is an array of numbers.
You can just iterate over them and build up a byte array by casting each of the numbers to byte.
Suppose you got your array of numbers into a int[] array using a JSON library of choice, simply do this:
int[] numbers = ...
byte[] bytes = new byte[numbers.length];
for (int i=0; i<numbers.length;i++) {
bytes[i] = (byte)numbers[i];
}
Here is the code:
The Classes are present in org.json package.
String jsonString = "{'template':[167,255,1,30,17,1,204,0,1,237,0,128,0] }";
JSONObject jObject = new JSONObject(jsonString);
JSONArray jArray = jObject.getJSONArray("template");
byte[] array = new byte[jArray.length()];
for(int i = 0; i < jArray.length(); i++) {
array[i] = (byte)jArray.getInt(i);
}
In OpenCV, the fastest way to work with a Mat is to first copy it to an array of the appropriate primitive type, something like this:
byte[][] array = new byte[rows][cols];
for (int i = 0; i < rows; i++) {
mat.get(i, 0, array[i]);
}
However, this doesn't work in OpenCV4Android with unsigned Mat types (e.g. 8U), since Java lacks unsigned types. I could just copy to an array of the next larger primitive type (here, a short) while adding 256 to every element:
byte[] buf = new byte[cols];
short[][] array = new short[rows][cols];
for (int i = 0; i < rows; i++) {
mat.get(i, 0, buf);
for (int j = 0; j < cols; j++) {
array[i][j] = (short) (buf[i]+256);
}
}
Is there a faster way?
It's actually possible to convert the Mat to signed byte before extracting it:
mat.convertTo(mat, CvType.CV_8S);
While indeed Java doesn't support unsigned primitive types, this would make a difference only if you do actual arithmetics with the values. 8 bits are 8 bits, signed or unsigned. If you need to calculate something with the values, yes - you should use a larger type (in fact double of the original) to avoid overflows (signed byte -127:128, unsgined: 0:255) and you should do some conversion to get rid of the "sign part" ( in case of byte & 0xFF).
Edit: This is a general answer, I haven't used OpenCV4Android. While in specific cases it might make sense to work with unsigned types for memory consumption reasons, my guess is that a library will actually output the values you need in the correct form for the platform?
I have a an array of byte, size n, that really represents an array of short of size n/2. Before I write the array to a disk file I need to adjust the values by adding bias values stored in another array of short. In C++ I would just assign the address of the byte array to a pointer for a short array with a cast to short and use pointer arithmetic or use a union.
How may this be done in Java - I'm very new to Java BTW.
You could do the bit-twiddling yourself but I'd recommend taking a look at the ByteBuffer and ShortBuffer classes.
byte[] arr = ...
ByteBuffer bb = ByteBuffer.wrap(arr); // Wrapper around underlying byte[].
ShortBuffer sb = bb.asShortBuffer(); // Wrapper around ByteBuffer.
// Now traverse ShortBuffer to obtain each short.
short s1 = sb.get();
short s2 = sb.get(); // etc.
You can wrap your byte array with java.nio.ByteBuffer.
byte[] bytes = ...
ByteBuffer buffer = ByteBuffer.wrap( bytes );
// you may or may not need to do this
//buffer.order( ByteOrder.BIG/LITTLE_ENDIAN );
ShortBuffer shorts = buffer.asShortBuffer( );
for ( int i = 0, n=shorts.remaining( ); i < n; ++i ) {
final int index = shorts.position( ) + i;
// Perform your transformation
final short adjusted_val = shortAdjuster( shorts.get( index ) );
// Put value at the same index
shorts.put( index, adjusted_val );
}
// bytes now contains adjusted short values
The correct way to do this is using shifts. So
for (int i = 0; i < shorts.length; i++) {
shorts[i] = (short)((bytes[2*i] << 8) | bytes[2*i + 1]);
}
Also, it depends on the endian-ness of the stream in many respects. This may work better
I'm working with java.
I have a byte array (8 bits in each position of the array) and what I need to do is to put together 2 of the values of the array and get a value.
I'll try to explain myself better; I'm extracting audio data from a audio file. This data is stored in a byte array. Each audio sample has a size of 16 bits. If the array is:
byte[] audioData;
What I need is to get 1 value from samples audioData[0] and audioData[1] in order to get 1 audio sample.
Can anyone explain me how to do this?
Thanks in advance.
I'm not a Java developer so this could be completely off-base, but have you considered using a ByteBuffer?
Assume the LSB is at data[0]
int val;
val = (((int)data[0]) & 0x00FF) | ((int)data[1]<<8);
As suggested before, Java has classes to help you with this. You can wrap your array with a ByteBuffer and then get an IntBuffer view of it.
ByteBuffer bb = ByteBuffer.wrap(audioData);
// optional: bb.order(ByteOrder.BIG_ENDIAN) or bb.order(ByteOrder.LITTLE_ENDIAN)
IntBuffer ib = bb.asIntBuffer();
int firstInt = ib.get(0);
ByteInputStream b = new ByteInputStream(audioData);
DataInputStream data = new DataInputStream(b);
short value = data.readShort();
The advantage of the above code is that you can keep reading the rest of 'data' in the same way.
A simpler solution for just two values might be:
short value = (short) ((audioData[0]<<8) | (audioData[1] & 0xff));
This simple solution extracts two bytes, and pieces them together with the first byte being the higher order bits and the second byte the lower order bits (this is known as Big-Endian; if your byte array contained Little-Endian data, you would shift the second byte over instead for 16-bit numbers; for Little-Endian 32-bit numbers, you would have to reverse the order of all 4 bytes, because Java's integers follow Big-Endian ordering).
easier way in Java to parse an array of bytes to bits is JBBP usage
class Parsed { #Bin(type = BinType.BIT_ARRAY) byte [] bits;}
final Parsed parsed = JBBPParser.prepare("bit:1 [_] bits;").parse(theByteArray).mapTo(Parsed.class);
the code will place parsed bits of each byte as 8 bytes in the bits array of the Parsed class instance
You can convert to a short (2 bytes) by logical or-ing the two bytes together:
short value = ((short) audioData[0]) | ((short) audioData[1] << 8);
I suggest you take a look at Preon. In Preon, you would be able to say something like this:
class Sample {
#BoundNumber(size="16") // Size of the sample in bits
int value;
}
class AudioFile {
#BoundList(size="...") // Number of samples
Sample[] samples;
}
byte[] buffer = ...;
Codec<AudioFile> codec = Codecs.create(AudioFile.class);
AudioFile audioFile = codec.decode(buffer);
You can do it like this, no libraries or external classes.
byte myByte = (byte) -128;
for(int i = 0 ; i < 8 ; i++) {
boolean val = (myByte & 256) > 0;
myByte = (byte) (myByte << 1);
System.out.print(val ? 1 : 0);
}
System.out.println();
byte myByte = 0x5B;
boolean bits = new boolean[8];
for(int i = 0 ; i < 8 ; i++)
bit[i] = (myByte%2 == 1);
The results is an array of zeros and ones where 1=TRUE and 0=FALSE :)