Unable to generate Image from modified Byte array in java - java

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.

Related

Converting BitSet to Byte[]

I have a BitSet, which needs to be converted to a Byte[]. However, by using BitSet.toByteArray(), I don't get the correct output. I have tried converting the Byte[] to its binary form in order to check whether the Bitset and the binary form of the Byte[] are similiar.
public static void generate() {
BitSet temp1 = new BitSet(64);
for (int i = 0; i < 64; i++) {
if(i % 8 != 0 && i < 23) {
temp1.set(i, true);
}
}
StringBuilder s = new StringBuilder();
for (int i = 0; i < 64; i++) {
s.append(temp1.get(i) == true ? 1 : 0);
}
System.out.println(s);
byte[] tempByteKey1 = temp1.toByteArray();
for (byte b : tempByteKey1) {
System.out.print(Integer.toBinaryString(b & 255 | 256).substring(1));
}
}
Output:
Bitset: 0111111101111111011111100000000000000000000000000000000000000000
Converted Byte: 1111111011111110011111100000000000000000000000000000000000000000
They are both 64 bits, but the first 0 in the BitSet is placed somewhere else after the conversion. Why is this happening, and how can I fix it?
From BitSet#toByteArray() javadoc:
Returns a new byte array containing all the bits in this bit set.
More precisely, if..
byte[] bytes = s.toByteArray();
then
bytes.length == (s.length()+7)/8
and
s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)
for all n < 8 * bytes.length.
#return a byte array containing a little-endian representation of all the bits in this bit set
#since 1.7
Attention: toByteArray() doesn't even claim to know size(), it is only "reliable" regarding length()!
..So I would propose as implementation (alternative for your toBinaryString()) a method like:
static String toBinaryString(byte[] barr, int size) {
StringBuilder sb = new StringBuilder();
int i = 0;
for (; i < 8 * barr.length; i++) {
sb.append(((barr[i / 8] & (1 << (i % 8))) != 0) ? '1' : '0');
}
for (; i < size; i++) {
sb.append('0');
}
return sb.toString();
}
..to call it like:
System.out.println(toBinaryString(bitSet.toByteArray(), 64);
run:
0111111101111111011111100000000000000000000000000000000000000000
0111111101111111011111100000000000000000000000000000000000000000
BUILD SUCCESSFUL (total time: 0 seconds)

Extract then stack the high and low bytes from an array of image bytes

I'm relatively new to doing image compression on the byte level, and am currently working on a java image preprocessor that will take a bmp image, convert it to an 8-bit unsigned grayscale, then stack its bytes according to high and low before exporting and compressing it. After some extensive research and testing various methods of byte extraction, I'm still not seeing the results I need. Before I continue, it should be noted that all of these images are originally in DICOM format, and I'm using the ij.plugin.DICOM package to extract the pixel data as a bmp image.
The following description is represented by code bellow. Currently, I'm reading in the original image as a buffered image, converting it to grayscale, then getting the image bytes from the Raster. Then I take those bytes, and using some other code I found on stackoverflow and "converting" them to a String representation of binary bits. I then send that string to a character array. The next step might be extraneous, but I wanted to get your input before I removed it (since I'm new at this). I make a Bitset and iterate through the "binary" character array. If the character value is "1", I set that position in the BitSet to true. Then I send the BitSet to another byte array.
Then I make two new byte arrays, one for the high and one for the low byte. Using a for loop, I'm iterating over the "bit" array and storing every 4 "bits" in the high or low byte, depending on where we are in the array.
Lastly, I take the DICOM tag data, make a byte array from it, and then stack the tag array, the high byte array, and the low byte array together. My intended result is to have the image matrix be "split" with the top half containing all the high bytes and the bottom half containing all of the low bytes. I've been told that the tag bytes will be so small, they shouldn't affect the final outcome (I've tested the image without them, just to be sure, and there was no visible difference).
Below is the code. Please let me know if you have any questions, and I will modify my post accordingly. I've tried to include all relevant data. Let me know if you need more.
BufferedImage originalImage = getGrayScale(img.getBufferedImage());//returns an 8-bit unsigned grayscale conversion of the original image
byte[] imageInByte = ((DataBufferByte) originalImage.getRaster().getDataBuffer()).getData();
String binary = toBinary(imageInByte); //converts to a String representation of the binary bits
char[] binCharArray = binary.toCharArray();
BitSet bits = new BitSet(binCharArray.length);
for (int i = 0; i < binCharArray.length; i++) {
if (binCharArray[i] == '1') {
bits.set(i);
}
}
imageInByte = bits.toByteArray();
byte[] high = new byte[(int) imageInByte.length/2];
byte[] low = new byte[(int) imageInByte.length/2];
int highC = 0;
int lowC = 0;
boolean change = false; //start out storing in the high bit
//change will = true on very first run. While true, load in the high byte array. Else low byte
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
//old code from a previous attempt.
// for (int j = 0; j < imageInByte.length; j++) {
// byte h = (byte) (imageInByte[j] & 0xFF);
// byte l = (byte) ((imageInByte[j] >> 8) & 0xFF);
// high[j] = h;
// low[j] = l;
// }
OutputStream out = null;
//add this array to the image array. It goes at the beginning.
byte[] tagBytes = dicomTags.getBytes();
currProcessingImageTagLength = tagBytes.length;
imageInByte = new byte[high.length + low.length + tagBytes.length];
System.arraycopy(tagBytes, 0, imageInByte, 0, tagBytes.length);
System.arraycopy(high, 0, imageInByte, tagBytes.length, high.length);
System.arraycopy(low, 0, imageInByte, tagBytes.length + high.length, low.length);
BufferedImage bImageFromConvert = new BufferedImage(dimWidth, dimHeight, BufferedImage.TYPE_BYTE_GRAY);//dimWidth and dimHeight are the image dimensions, stored much earlier in this function
byte[] bufferHolder = ((DataBufferByte) bImageFromConvert.getRaster().getDataBuffer()).getData();
System.arraycopy(imageInByte, 0, bufferHolder, 0, bufferHolder.length);
//This is where I try and write the final image before sending it off to an image compressor
ImageIO.write(bImageFromConvert, "bmp", new File(
directory + fileName + "_Compressed.bmp"));
return new File(directory + fileName + "_Compressed.bmp");
And below is the toBinary function in case you were interested:
private static String toBinary(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
for (int i = 0; i < Byte.SIZE * bytes.length; i++) {
sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
}
return sb.toString();
}
Thank you so much for your help! I've spent nearly 20 hours now trying to solve this one problem. It's been a huge headache, and any insight you have would be appreciated.
EDIT: Here's the getGreyScale function:
public static BufferedImage getGrayScale(BufferedImage inputImage) {
BufferedImage img = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img.getGraphics();
g.drawImage(inputImage, 0, 0, null);
g.dispose();
return img;
}
EDIT 2: I've added some images upon request.
Current output:
current image
Note, I can't post the images with the "expected" high byte and low byte outcome due to my reputation being lower than 10.
This says every 4 bytes change; thats not what you intend:
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
I would replace it with this, from your earlier attempt
for (int j = 0; j < imageInByte.length; j+=2) {
byte h = (byte) (imageInByte[j] & 0xF0);
byte h2 = (byte) (imageInByte[j+1] & 0xF0);
byte l = (byte) (imageInByte[j] & 0x0f);
byte l2 = (byte) (imageInByte[j+1] & 0x0f);
high[j/2] = h|(h2>>4);
low[j/2] = (l<<4)|l2;
}

Which byte(Alpha, Red, Green, Blue) is wrong when converting byte array with color space of 8BitARGB to BufferedImage.TYPE_4BYTE_ABGR

I have got the image byte array in the color space of 8BitARGB and need to convert this byte array to java.awt.BufferedImage.
The code is like:
public void getImage(byte byteArray[]){
int height = 1920;
int width = 1080;
ARGB_to_ABGR(byteArray);
BufferedImage image1 = new BufferedImage(height, width,
BufferedImage.TYPE_4BYTE_ABGR);
image1.getWritableTile(0, 0).setDataElements(0, 0, height, width, byteArray);
java.io.File file = new java.io.File("amazing.png");
try {
ImageIO.write(image1, "jpg", file);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
/*
* Swap the Red byte and Blue byte
*/
public void ARGB_to_ABGR(byte byteArray[]){
int length = byteArray.length;
byte r = 0;
byte b = 0;
for(int i = 0; i < byteArray.length; i++){
if(length % 4 == 0){
//do nothing
}else if(length % 4 == 1){
r = byteArray[i];
}else if(length % 4 == 2){
//do nothing
}else if(length % 4 == 3){
b = byteArray[i];
byteArray[i] = r;
byteArray[i - 2] = b;
}
}
}
The original image looks like:
The amazing.png looks like:
I don't think the original byte array has any problem. For quick debug, just based on the image effect,can anyone tell which byte(Alpha, Red, Green, Blue) is wrong? Thanks for your help in advance.
In the code for ARGB_to_ABGR you probably wanted to write i % 4 where you now have length % 4. As it is currently, I guess it is doing nothing at all.
I think #Henry is right in that there's just a simple typo in your code. However, I'd like to provide an alternative way of writing this, which is (to me at least) easier to read/understand, and thus less error prone.
I believe it's also faster, as it does no testing on the indexes.
This version iterates over the input byte array one pixel (4 bytes) at a time:
public void ARGB_to_ABGR(byte[] byteArray) {
byte tempR = 0;
for (int i = 0; i < byteArray.length; i += 4) {
// For each iteration, simply swap R and B
tempR = byteArray[i + 1];
byteArray[i + 1] = byteArray[i + 3];
byteArray[i + 3] = tempR;
}
}

Java: convert byte[] to base36 String

I'm a bit lost. For a project, I need to convert the output of a hash-function (SHA256) - which is a byte array - to a String using base 36.
So In the end, I want to convert the (Hex-String representation of the) Hash, which is
43A718774C572BD8A25ADBEB1BFCD5C0256AE11CECF9F9C3F925D0E52BEAF89
to base36, so the example String from above would be:
3SKVHQTXPXTEINB0AT1P0G45M4KI8U0HR8PGB96DVXSTDJKI1
For the actual conversion to base36, I found some piece of code here on StackOverflow:
public static String toBase36(byte[] bytes) {
//can provide a (byte[], offset, length) method too
StringBuffer sb = new StringBuffer();
int bitsUsed = 0; //will point how many bits from the int are to be encoded
int temp = 0;
int tempBits = 0;
long swap;
int position = 0;
while((position < bytes.length) || (bitsUsed != 0)) {
swap = 0;
if(tempBits > 0) {
//there are bits left over from previous iteration
swap = temp;
bitsUsed = tempBits;
tempBits = 0;
}
//fill some bytes
while((position < bytes.length) && (bitsUsed < 36)) {
swap <<= 8;
swap |= bytes[position++];
bitsUsed += 8;
}
if(bitsUsed > 36) {
tempBits = bitsUsed - 36; //this is always 4
temp = (int)(swap & ((1 << tempBits) - 1)); //get low bits
swap >>= tempBits; //remove low bits
bitsUsed = 36;
}
sb.append(Long.toString(swap, 36));
bitsUsed = 0;
}
return sb.toString();
}
Now I'm doing this:
// this creates my hash, being a 256-bit byte array
byte[] hash = PBKDF2.deriveKey(key.getBytes(), salt.getBytes(), 2, 256);
System.out.println(hash.length); // outputs "256"
System.out.println(toBase36(hash)); // outputs total crap
the "total crap" is something like
-7-14-8-1q-5se81u0e-3-2v-24obre-73664-7-5-5cor1o9s-6h-4k6hr-5-4-rt2z0-30-8-2u-8-onz-4a2j-6-8-18-8trzza3-3-2x-6-4153to-4e3l01me-6-azz-2-k-4ckq-nav-gu-irqpxx-el-1j-6-rmf8hs-1bb5ax-3z25u-2-2r-t5-22-6-6w1v-1p
so it's not even close to what I want. I tried to find a solution now, but it seems I'm a bit lost here. How do I get the base36-encoded String representation of the Hash that I need?
Try using BigInteger:
String hash = "43A718774C572BD8A25ADBEB1BFCD5C0256AE11CECF9F9C3F925D0E52BEAF89";
//use a radix of 16, default would be 10
String base36 = new BigInteger( hash, 16 ).toString( 36 ).toUpperCase();
This might work:
BigInteger big = new BigInteger(your_byte_array_to_hex_string, 16);
big.toString(36);

Converting Bytes To BitSets

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.

Categories

Resources