Converting byte array to png

2020-03-31 07:13发布

问题:

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)

回答1:

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.