Best way to convert RGB byte[][] image to byte[] - java

Have frame data in the form of a byte[][] object, where each row corresponds to a (R,G,B) channel and is of length (frame width*frame height). I wish to convert it to a byte[] format in a similar vein as follows:
byte[][] original_frame;
byte[] converted_frame = convert(original_frame);
ByteArrayInputStream bis = new ByteArrayInputStream(frame);
BufferedImage bImage2 = ImageIO.read(bis);
From what I can tell, ImageIO assumes a jpeg format. Do I need to convert every frame to a JPEG image, or is there a more natural way to do this?

I believe that you are asking how to convert from a 2D array to 1D array. How to do this if all rows are length 3 is as follows:
ArrayList<byte> x = new ArrayList<byte>();
for(int i=0; i<original_frame.length; i++){
x.add(original_frame[i][0]);
x.add(original_frame[i][1]);
x.add(original_frame[i][2]);
}
byte[] converted_frame= new byte[x.size()];
for(int i=0;i<x.size();i++){
converted_frame[i]=x.get(i);
}
I hope this helps

Related

Converting byte array to png

I have a byte array obtained from an image using the following code.
String path = "/home/mypc/Desktop/Steganography/image.png";
File file = new File(path);
BufferedImage bfimage = ImageIO.read(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bfimage, "png", baos);
baos.flush();
byte[] img_in_bytes = baos.toByteArray();
baos.close();
Then I converted these bytes back to png image using the following code.
BufferedImage final_img = ImageIO.read(new ByteArrayInputStream(img_in_bytes));
File output_file = new File("Stegano2.png");
ImageIO.write(final_img, "png", output_file);
It is perfectly fine if i just execute this piece of code. But if i try to modify some of the bytes in between, say like this :
Insert_number_to_image(image_in_bytes, 10);
and my method "Inset_number_to_image" goes like this :
static void Insert_number_to_image(byte[] image, int size){
byte[] size_in_byte = new byte[4];
size_in_byte[0] = (byte)(size >>> 0);
size_in_byte[1] = (byte)(size >>> 8);
size_in_byte[2] = (byte)(size >>> 16);
size_in_byte[3] = (byte)(size >>> 24);
byte temp;
int count = 0;
for(int i=0; i<4; i++)
{
for(int j=0; j<8; j++)
{
temp = size_in_byte[i];
temp = (byte)(temp >>> j);
temp = (byte)(temp & 1);
if(temp == 1)
{
image[count] = (byte)(image[count] | 1);
}
else if(temp == 0)
{
image[count] = (byte)(image[count] & (byte)(~(1)));
}
count++;
}
}
}
then after that, when i save the modified byte array as png image using same code mentioned above, i am getting this error :
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1591)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
at Steganography.main(Steganography.java:211)
What you're using is the raw bytestream of a PNG image. PNG is a compressed format, where the bytestream doesn't reflect any of the pixel values directly and even changing one byte might irreversibly corrupt the file.
What you want instead is to extract the pixel data to a byte array with
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
Now you can modify the pixel values however you want. When you are ready to save that back to a file, convert the pixel byte array to a BufferedImage by putting your pixel array in a DataBufferByte object and passing that to a WriteableRaster, which you then use to create a BufferedImage.
Your method would work for formats where the raw bytestream does directly represent the pixels, such as in BMP. However, even then you'd have to skip the first few bytes to avoid corrupting the header.

Convert ByteArrayOutputStream to int values

I am constantly trying to convert a ByteArrayOutputStream to int values.
I am recording an Audio with microphone and writing it to out = new ByteArrayOutputStream() like so:
out.write(buffer, 0, count);
byte audio[] = out.toByteArray();
When I print this I get these : [B#3456337e
How do I convert these to integer numbers.
Please Help, Thanks
There is no standard way to do it because actually it depends on what kind of bytes you have but, as it is an audio source, I think you can do it like that :
IntBuffer intBuf =
ByteBuffer.wrap(byteArray)
.order(ByteOrder.BIG_ENDIAN) //or try ByteOrder.LITTLE_ENDIAN
.asIntBuffer();
int[] array = new int[intBuf.remaining()];
intBuf.get(array);
//The result you want is "array"
I hope it will help you.
Convert it to an array, wrap the array in a ByteArrayInputStream, wrap that in a DataInputStream, and use readInt().
Try the following -
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataInputStream dataIs = new DataInputStream
(new ByteArrayInputStream(out.toByteArray());
// available stream to be read
while(dataIs.available()>0)
{
int k = dataIs.readInt();
// print int
System.out.print(k+" ");
}

Java: retrieving byte array from an 8 bit wav file and normalizing it to -1.0 to 1.0

Bear with me as Im very new with working with audio and I have been googling for days for a solution and not finding any.
So i retrieve the byte array of a .wav file with this (source: Wav file convert to byte array in java)
ByteArrayOutputStream out = new ByteArrayOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(WAV_FILE));
int read;
byte[] buff = new byte[1024];
while ((read = in.read(buff)) > 0)
{
out.write(buff, 0, read);
}
out.flush();
byte[] audioBytes = out.toByteArray();
And then i convert the byte array to a float array and normalize it from -1.0 to 1.0. (source: Convert wav audio format byte array to floating point)
ShortBuffer sbuf =
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);
float[] audioFloats = new float[audioShorts.length];
for (int i = 0; i < audioShorts.length; i++) {
audioFloats[i] = ((float)audioShorts[i])/0x8000;
}
return audioFloats;
Later i convert this to line drawings which outputs the waveform using java.swing
class Panel2 extends JPanel {
float[] audioFloats;
Dimension d;
public Panel2(Dimension d, float[] audioFloats) {
// set a preferred size for the custom panel.
this.d = d;
setPreferredSize(d);
this.audioFloats = audioFloats;
}
#Override
public void paint(Graphics g) {
//super.paintComponent(g);
super.paint(g);
//shift by 45 because first 44 bytes used for header
for (int i = 45; i<audioFloats.length; i++){
Graphics2D g2 = (Graphics2D) g;
float inc = (i-45)*((float)d.width)/((float)(audioFloats.length-45-1));
Line2D lin = new Line2D.Float(inc, d.height/2, inc, (audioFloats[i]*d.height+d.height/2));
g2.draw(lin);
}
}
}
The waveform only looks right for 16 bit wav files (ive cross checked with goldwave and both my waveform and their waveform look similar for 16 bits).
How do i do this for 8 bit .wav files?
Because this is for homework, my only restriction is read the wav file byte by byte.
I also know the wav files are PCM coded and have the first 44 bytes reserved as the header
You need to adapt this part of the code:
ShortBuffer sbuf =
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);
float[] audioFloats = new float[audioShorts.length];
for (int i = 0; i < audioShorts.length; i++) {
audioFloats[i] = ((float)audioShorts[i])/0x8000;
}
You don't need ByteBuffer at all—you already have your byte array. So just convert it to floats:
float[] audioFloats = new float[audioBytes.length];
for (int i = 0; i < audioBytes.length; i++) {
audioFloats[i] = ((float)audioBytes[i])/0x80;
}
Audio streams are usually interleaved with one channel of data then the opposite channel of data. So for example the first 16 bits would be the left channel, then the next 16 bits would be the right channel. Each of these is considered 1 frame of data. I would make sure that your 8 bit stream is only one channel because it looks like the methods are only set up to read one channel.
Also in your example to convert the frames you are grabbing the individual channel as a short then finding a decimal by dividing that by 0x8000 hex or the maximum value of a signed short.
short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);
...
audioFloats[i] = ((float)audioShorts[i])/0x8000;
My guess is that you need to read the 8 byte stream as a type 'byte' instead of a short then divide that by 128 or the maximum value of a signed 8 bit value. This will involve making a whole new method that processes 8 bit streams instead of 16 bit streams. With the following changes.
byte[] audioBytes = new byte[sbuf.capacity()];
sbuf.get(audioBytes);
...
audioFloats[i] = ((float)audioBytes[i])/0x80;

Saving short[] in java (android) with low cpu and space

while streaming music i'm getting pcm data as type short[] and i want to save it to file in my android device so i can play it again later (using AudioTrack). i wan't the store of the music to be efficent in memory and cpu.
how to save short[] to file cause i dont see any function in.write(short[])?
how can i decrease the space\cpu for saving this file?
Wrap your FileOutputStream with DataOutputStream:
DataOutputStream doStream = new DataOutputStream(new BufferedOutputStream(fileOutputStream));
doStream.writeInt(numberArray.length); //Save size
for (int i=0;i<numberArray.length;i++) {
doStream.writeShort(numberArray[i]); //Save each number
}
Same way for reading it back:
DataInputStream diStream = new DataInputStream(new BufferedInputStream(fileInputStream));
int size = diStream.readInt(); //Read size
short[] data = new short[size]; //Create new array with required length
for (int i=0;i<size;i++) {
data[i] = diStream.readShort(); //Read each number
}
Without any encoding to MP3 or similar you can always do like this.
short[] sound = ...;
ByteBuffer byteMyShorts = ByteBuffer.allocate(sound.length * 2);
ShortBuffer shortBytes = byteMyShorts.asShortBuffer();
shortBytes.put(sound);
byteMyShorts.flip();
// byteMyShorts.array() now contains your short[] array as an
// array of bytes.

About java ByteArrayOutputStream class

BufferedImage bufferedImage = ImageIO.read(new File("/...icon.jpg"));
// this writes the bufferedImage into a byte array called resultingBytes
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", byteArrayOut);
byte[] resultingBytes = byteArrayOut.toByteArray();
I use the above code to get a JEPG image as a byte array. I want to know what exactly is in this byte array. Does this array contain any file header information or just pixel values? And for example, if I want to reverse this image's color, what is a good way to do so?
Thanks so much!
It's a complete JPEG file, in memory.
EDIT: If you want to manipulate pixel data as an array, you may find Raster more helpful:
E.g.:
Raster raster = bufferedImage.getData();
You can then call one of the Raster.getPixels methods.
The ByteArrayOutputStream contains whatever you wrote to it. Nothing more, nothing less. So your question is really about ImageIO.write(). Which writes out an encoding of an image according to the encoding type you supply. Which was JPEG.
Here is how you read real pixel values. The JPEG information is much harder to do anything with!
public static void main(String... args) throws IOException {
String u = "http://blog.stackoverflow.com/wp-content/uploads/stackoverflow-logo-300.png";
BufferedImage old = ImageIO.read(new URL(u));
BufferedImage inverted = new BufferedImage(old.getWidth(),
old.getHeight(),
BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < old.getHeight(); y++) {
for (int x = 0; x < old.getWidth(); x++) {
Color oldColor = new Color(old.getRGB(x, y));
// reverse all but the alpha channel
Color invertedColor = new Color(255 - oldColor.getRed(),
255 - oldColor.getGreen(),
255 - oldColor.getBlue());
inverted.setRGB(x, y, invertedColor.getRGB());
}
}
ImageIO.write(inverted, "png", new File("test.png"));
}

Categories