I need to divide a byte array into 3 parts and process them one by one
The first 120 data array is filled in callback function of a Bluetooth device read request, so it's impossible for me to change
byte[] data = new byte[120];
------
byte[] buf = new byte[40];
for (int i = 0; i < 3; ++i) {
System.arraycopy(data, i * 40, packetBuffer, 0, 40);
processDataStream(buf);
}
If in c/c++, I can use pointer so no need to call copy.
In Java, is arraycopy the best way? is there any more efficient way?
Thanks in advance
In most cases you'd just specify an offset and provide it to your method:
byte[] buf = new byte[40];
for (int i = 0; i < 3; ++i) {
processDataStream(buf, i * 40);
}
Then you only need to apply it:
processDataStream(byte[] buf, int offset) {
for (int i = offset; i < offset + 40; i++) {
...
}
}
Related
In my code I'm reading image convert it to byte array and modifying that byte array with some logic and trying to generate image from that modified byte array, but i'm unable to generate image from that code
my code sample:
//1. Convert Image to byte code
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedImage img=ImageIO.read(new File(dirName,"MyImg.png"));
ImageIO.write(img, "png", baos);
baos.flush();
byte[] bytes = baos.toByteArray();
byte[] modified = baos.toByteArray();
String temp_string = new String();
for (int i = 0; i < bytes.length; i++)
{
// conversion of byte to unsign byte
int b = bytes[i] & 0xFF;
/*
* convert byte array to an 8 bit string
*/
int temp,count = 1;
byte b1 = (byte)b;
String uv = String.format("%8s", Integer.toBinaryString(b1 & 0xFF)).replace(' ', '0');
String tempStr = "";
for(int zx = 0 ; zx < uv.length() ; zx++ )
{
temp = Character.getNumericValue(uv.charAt(zx));
if(temp == 1)
{
temp += count;
count = temp;
if(temp % 2 == 0)
temp = 0;
else
temp = 1;
tempStr += temp;
}
else if(temp == 0)
{
tempStr += 0;
}
}
temp_string += tempStr;
if(i < bytes.length)
{
temp_string +=",";
}
}
String[] string_ByteArray = temp_string.split(",");
for(int a =0 ; a < string_ByteArray.length ; a++)
{
int aaa = Integer.parseInt(string_ByteArray[a],2);
modified[a] = (byte) aaa;
}
//3. Convert byte code to Image
ByteArrayInputStream bis = new ByteArrayInputStream(modified);
BufferedImage bImage2 = ImageIO.read(bis);
ImageIO.write(bImage2, "png", new File("output.png") );
in this code i'm getting error in 3rd step:
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(Unknown Source)
at javax.imageio.ImageIO.getWriter(Unknown Source)
at javax.imageio.ImageIO.write(Unknown Source)
at mypack.Img_conversion.main(Img_conversion.java:96)
That is an impressively roundabout way of doing bit manipulation. There is no valid reason to use Strings. I suggest you either use bitwise operators, or use a BitSet.
Iterating through bits mathematically:
int b = bytes[i] & 0xFF;
for (int j = 7; j >= 0; j--) {
int bit = (b >> j) & 1;
temp = /* ... */;
if (temp != 0) {
b |= (1 << j); // set bit j
} else {
b &= ~(1 << j); // clear bit j
}
}
modified[i] = (byte) b;
Iterating through bits with a BitSet:
byte b = bytes[i];
BitSet bits = BitSet.valueOf(new byte[] { b });
for (int j = 7; j >= 0; j--) {
int bit = bits.get(j) ? 1 : 0;
temp = /* ... */;
bits.set(j, temp != 0);
}
modified[i] = bits.toByteArray()[0];
You might notice that since BitSet.valueOf takes an array of bytes, it’s wasteful to keep creating new BitSets. Instead, you could just do BitSet.valueOf(bytes) once, and run through all the bits in that single BitSet:
BitSet bits = BitSet.valueOf(bytes);
for (int i = bits.cardinality() - 1; i >= 0; i--) {
int bit = bits.get(i) ? 1 : 0;
temp = /* ... */;
bits.set(i, temp != 0);
}
byte[] modified = bits.toByteArray();
However…
A PNG image is (usually) compressed. This means the bits do not directly correspond to pixels. Modifying those bits creates an invalid compressed data block, which is why your attempt to read it with ImageIO.read fails and returns null.
If you want bytes you can directly manipulate, get them from the raw BufferedImage, not from a PNG representation:
int[] pixels = img.getData().getPixels(
0, 0, img.getWidth(), img.getHeight(),
new int[0]);
byte[] bytes = pixels.length * 4;
ByteBuffer.wrap(bytes).asIntBuffer().put(pixels);
It would be much easier for others to help you, if you took the time to give your variables meaningful names. temp and uv and zx are cryptic and meaningless. Better names would be:
temp_string → allByteValues
uv → bitsOfByte
tempStr → newBits
zx → bitIndex (or just a typical secondary indexing variable, like j)
temp → bit
When you’re done modifying the bytes, you still have raw image data, not a PNG representation, so you cannot make a ByteArrayInputStream from those bytes and pass them to ImageIO.read. Attempting to pass off those bytes as a PNG representation will always fail.
Instead, overwrite your image with the pixel data:
int[] pixels = new int[bytes.length / 4];
ByteBuffer.wrap(bytes).asIntBuffer().get(pixels);
img.getRaster().setPixels(0, 0, img.getWidth(), img.getHeight(), pixels);
ImageIO.write(img, "png", new File("output.png"));
As stated in the documentation if any of the parameter of the write method is null it will throw IllegalArgumentException.
You call like this:
ImageIO.write(bImage2, "png", new File("output.png") );
The only parameter which can be null is the bImage2.
Please check it if it's really null.
I have a problem with this method
private static boolean getBlocks(File file1, File file2) throws IOException {
FileChannel channel1 = new FileInputStream(file1).getChannel();
FileChannel channel2 = new FileInputStream(file2).getChannel();
int SIZE = (int) Math.min((8192), channel1.size());
int point = 0;
MappedByteBuffer buffer1 = channel1.map(FileChannel.MapMode.READ_ONLY, 0, channel1.size());
MappedByteBuffer buffer2 = channel2.map(FileChannel.MapMode.READ_ONLY, 0, channel2.size());
byte [] bytes1 = new byte[SIZE];
byte [] bytes2 = new byte[SIZE];
while (point < channel1.size() - SIZE) {
buffer1.get(bytes1, point, SIZE);
buffer2.get(bytes2, point, SIZE);
if (!compareBlocks(bytes1, bytes2)) {
return false;
}
point += SIZE;
}
return true;
}
private static boolean compareBlocks (byte[] bytes1, byte[] bytes2) {
for (int i = 0; i < bytes1.length; i++) {
if (bytes1[i] != bytes2[i]) {
return false;
}
}
return true;
}
In a result I caught IndexOutOfBoundsException in while loop.
How can I get around this problem and compare two files by blocks?
Yeah... it has to crap.
You create a byte array with 'SIZE' length and access it's position with point var which increments with 'SIZE' vallue.
For example:
int SIZE = 10;
int point = 0;
while( point < channel.size() - SIZE ){
buffer1.get(bytes1, point, SIZE);
// Your logic here
point += SIZE;
}
When you do the above, SIZE vallue increments enourmously and you try to access the byte array with point position which will have a higher vallue than it's size.
So, your logic to access the array position is wrong. As the error line says, you're accessing and index out of bounds( higher than the limit ).
I hope I could help you.
How can I remove the first n number of bytes from a ByteBuffer without changing or lowering the capacity? The result should be that the 0th byte is the n+1 byte. Is there a better data type in Java to do this type of action?
You could try something like this:
public void removeBytesFromStart(ByteBuffer bf, int n) {
int index = 0;
for(int i = n; i < bf.position(); i++) {
bf.put(index++, bf.get(i));
bf.put(i, (byte)0);
}
bf.position(index);
}
Or something like this:
public void removeBytesFromStart2(ByteBuffer bf, int n) {
int index = 0;
for(int i = n; i < bf.limit(); i++) {
bf.put(index++, bf.get(i));
bf.put(i, (byte)0);
}
bf.position(bf.position()-n);
}
This uses the absolute get and put method of the ByteBuffer class and sets the position at next write position.
Note that the absolute put method is optional, which means that a class that extends the abstract class ByteBuffer may not provide an implementation for it, for example it might throw a ReadOnlyBufferException.
Whether you choose to loop till position or till limit depends on how you use the buffer, for example if you manually set the position you might want to use loop till limit. If you do not then looping till position is enough and more efficient.
Here is some testings:
#Test
public void removeBytesFromStart() {
ByteBuffer bf = ByteBuffer.allocate(16);
int expectedCapacity = bf.capacity();
bf.put("abcdefg".getBytes());
ByteBuffer expected = ByteBuffer.allocate(16);
expected.put("defg".getBytes());
removeBytesFromStart(bf, 3);
Assert.assertEquals(expectedCapacity, bf.capacity());
Assert.assertEquals(0, bf.compareTo(expected));
}
#Test
public void removeBytesFromStartInt() {
ByteBuffer bf = ByteBuffer.allocate(16);
int expectedCapacity = bf.capacity();
bf.putInt(1);
bf.putInt(2);
bf.putInt(3);
bf.putInt(4);
ByteBuffer expected = ByteBuffer.allocate(16);
expected.putInt(2);
expected.putInt(3);
expected.putInt(4);
removeBytesFromStart2(bf, 4);
Assert.assertEquals(expectedCapacity, bf.capacity());
Assert.assertEquals(0, bf.compareTo(expected));
}
I think the method you are looking for is the ByteBuffer's compact() method
Even though the documentation says:
"The bytes between the buffer's current position and its limit, if any, are copied to the beginning of the buffer. That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one, and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer's position is then set to n+1 and its limit is set to its capacity."
I am not sure that this method realy does that, because when I debug it seems like the method just does buffer.limit = buffer.capacity.
Do you mean to shift all the element to the begining of the buffer? Like this:
int n = 4;
//allocate a buffer of capacity 10
ByteBuffer b = ByteBuffer.allocate(10);
// add data to buffer
for (int i = 0; i < b.limit(); i++) {
b.put((byte) i);
}
// print buffer
for (int i = 0; i < b.limit(); i++) {
System.out.print(b.get(i) + " ");
}
//shift left the elements from the buffer
//add zeros to the end
for (int i = n; i < b.limit() + n; i++) {
if (i < b.limit()) {
b.put(i - n, b.get(i));
} else {
b.put(i - n, (byte) 0);
}
}
//print buffer again
System.out.println();
for (int i = 0; i < b.limit(); i++) {
System.out.print(b.get(i) + " ");
}
For n=4 it will print:
0 1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 0 0 0 0
Use compact method for that. E.g.:
ByteBuffer b = ByteBuffer.allocate(32);
b.put("hello,world".getBytes());
b.position(6);
b.compact();
System.out.println(new String(b.array()));
I am trying to figure out a way of taking data from a file and I want to store every 4 bytes as a bitset(32). I really have no idea of how to do this. I have played about with storing each byte from the file in an array and then tried to covert every 4 bytes to a bitset but I really cannot wrap my head around using bitsets. Any ideas on how to go about this?
FileInputStream data = null;
try
{
data = new FileInputStream(myFile);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead;
while ((bytesRead = data.read(b)) != -1)
{
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
Ok, you got your byte array. Now what you have to convert each byte to a bitset.
//Is number of bytes divisable by 4
bool divisableByFour = bytes.length % 4 == 0;
//Initialize BitSet array
BitSet[] bitSetArray = new BitSet[bytes.length / 4 + divisableByFour ? 0 : 1];
//Here you convert each 4 bytes to a BitSet
//You will handle the last BitSet later.
int i;
for(i = 0; i < bitSetArray.length-1; i++) {
int bi = i*4;
bitSetArray[i] = BitSet.valueOf(new byte[] { bytes[bi], bytes[bi+1], bytes[bi+2], bytes[bi+3]});
}
//Now handle the last BitSet.
//You do it here there may remain less than 4 bytes for the last BitSet.
byte[] lastBitSet = new byte[bytes.length - i*4];
for(int j = 0; j < lastBitSet.length; j++) {
lastBitSet[i] = bytes[i*4 + j]
}
//Put the last BitSet in your bitSetArray
bitSetArray[i] = BitSet.valueOf(lastBitSet);
I hope this works for you as I have written quickly and did not check if it works. But this gives you the basic idea, which was my intention at the beginning.
Recently, I've been experimenting with mixing AudioInputStreams together. After reading this post, or more importantly Jason Olson's answer, I came up with this code:
private static AudioInputStream mixAudio(ArrayList audio) throws IOException{
ArrayList<byte[]> byteArrays = new ArrayList();
long size = 0;
int pos = 0;
for(int i = 0; i < audio.size(); i++){
AudioInputStream temp = (AudioInputStream) audio.get(i);
byteArrays.add(convertStream(temp));
if(size < temp.getFrameLength()){
size = temp.getFrameLength();
pos = i;
}
}
byte[] compiledStream = new byte[byteArrays.get(pos).length];
for(int i = 0; i < compiledStream.length; i++){
int byteSum = 0;
for(int j = 0; j < byteArrays.size(); j++){
try{
byteSum += byteArrays.get(j)[i];
}catch(Exception e){
byteArrays.remove(j);
}
}
compiledStream[i] = (byte) (byteSum / byteArrays.size());
}
return new AudioInputStream(new ByteArrayInputStream(compiledStream), ((AudioInputStream)audio.get(pos)).getFormat(), ((AudioInputStream)audio.get(pos)).getFrameLength());
}
private static byte[] convertStream(AudioInputStream stream) throws IOException{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int numRead;
while((numRead = stream.read(buffer)) != -1){
byteStream.write(buffer, 0, numRead);
}
return byteStream.toByteArray();
}
This code works very well for mixing audio files. However, it seems the more audio files being mixed, the more white noise that appears in the returned AudioInputStream. All of the files being combined are identical when it comes to formatting. If anyone has any suggestions\advice, thanks in advance.
I could be wrong, but I think your problem has to do with the fact that you are messing with the bytes instead of what the bytes mean. For instance, if you are working with a 16 bit sampling rate, 2 bytes form the number that corresponds to the amplitude rather than just 1 byte. So, you end up getting something close but not quite right.