How to convert image byte array into a bitmap after altering with the byte array

0

I am trying to implement Steganography in Android and I have implemented the code to encode the image bit by bit.

private Bitmap add_text(Bitmap image, String text)
{
    //convert all items to byte arrays: image, message, message length
    byte img[]  = get_byte_data(image);
    byte msg[] = text.getBytes();
    byte len[]   = bit_conversion(msg.length);
    displaybit(img, "Start");

    try
    {
        encode_text(img, len,  0); //0 first positiong
        encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits

        return BitmapFactory.decodeByteArray(img, 0, img.length);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return image;
}

private byte[] get_byte_data(Bitmap image)
{
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    image.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    return stream.toByteArray();
}

private byte[] bit_conversion(int i)
{
    //originally integers (ints) cast into bytes
    //byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56);
    //byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48);
    //byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40);
    //byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32);

    //only using 4 bytes
    byte byte3 = (byte)((i & 0xFF000000) >>> 24); //0
    byte byte2 = (byte)((i & 0x00FF0000) >>> 16); //0
    byte byte1 = (byte)((i & 0x0000FF00) >>> 8 ); //0
    byte byte0 = (byte)((i & 0x000000FF)       );
    //{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0
    return(new byte[]{byte3,byte2,byte1,byte0});
}

private byte[] encode_text(byte[] image, byte[] addition, int offset)
{
    //check that the data + offset will fit in the image
    if(addition.length + offset > image.length)
    {
        throw new IllegalArgumentException("File not long enough!");
    }
    //loop through each addition byte
    for(int i=0; i<addition.length; ++i)
    {
        //loop through the 8 bits of each byte
        int add = addition[i]; //0
        for(int bit=7; bit>=0; --bit, ++offset) //ensure the new offset value carries on through both loops
        {
            //assign an integer to b, shifted by bit spaces AND 1
            //a single bit of the current byte
            int b = (add >>> bit) & 1;
            //assign the bit by taking: [(previous byte value) AND 0xfe] OR bit to add
            //changes the last bit of the byte in the image to be the bit of addition
            image[offset] = (byte)((image[offset] & 0xFE) | b );
        }
    }
    return image;
}

But I am not able to form a bitmap after encoding the data into the image.

I have implemented the same algorithm in java and it works fine:

private BufferedImage add_text(BufferedImage image, String text)
{
    //convert all items to byte arrays: image, message, message length
    byte img[]  = get_byte_data(image);
    byte msg[] = text.getBytes();
    byte len[]   = bit_conversion(msg.length);
    try
    {
        encode_text(img, len,  0); //0 first positiong
        encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits
    }
    catch(Exception e)
    {
        JOptionPane.showMessageDialog(null, 
"Target File cannot hold message!", "Error",JOptionPane.ERROR_MESSAGE);
    }
    return image;
}

So could some one please help me figure out why the byte array is invalid in the case of android.

java
android
arrays
bitmap
steganography
asked on Stack Overflow Feb 21, 2018 by Satyam Rai • edited Feb 21, 2018 by Satyam Rai

2 Answers

1

You start with a byte[] of JPEG data. You then modify that data, changing bits semi-randomly, without regard to the JPEG data format. You then attempt to decode the modified byte[]. Not surprisingly, BitmapFactory cannot decode it, as it is no longer a valid image format.

My best guess is that you think that the byte[] is raw pixels in ARGB format.

If that is the case, then use methods like getPixel() and setPixel() on Bitmap to modify the pixels, and skip the bitmap encoding and decoding steps.

answered on Stack Overflow Feb 21, 2018 by CommonsWare
0

I was finally able to figure it out, as mentioned above in the comment the solution was solving it pixel by pixel. So I took a pixel and put the data in its rgb value bit by bit. So this is the code:

private Bitmap add_text(Bitmap image, String text, File tempFile) {
    //convert all items to byte arrays: image, message, message length
    byte msg[] = text.getBytes();
    byte len[] = bit_conversion(msg.length);

    try {

        return encodeTextRGB(image, len, msg, tempFile);

    } catch (Exception e) {
        e.printStackTrace();
    }
    return image;
}

private byte[] bit_conversion(int i) {
    //originally integers (ints) cast into bytes
    //byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56);
    //byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48);
    //byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40);
    //byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32);

    //only using 4 bytes
    byte byte3 = (byte) ((i & 0xFF000000) >>> 24); //0
    byte byte2 = (byte) ((i & 0x00FF0000) >>> 16); //0
    byte byte1 = (byte) ((i & 0x0000FF00) >>> 8); //0
    byte byte0 = (byte) ((i & 0x000000FF));
    //{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0
    return (new byte[]{byte3, byte2, byte1, byte0});
}

public Bitmap encodeTextRGB(Bitmap buffer, byte[] len, byte[] data, File tempFile) {

    pixelRow = 0;
    pixelCol = 0;

    byte[] overhead = len;

    int bitCount = 0;
    int iteration = 0;

    while (iteration++ < 2) {
        for (int i = 0; i < overhead.length; i++) {
            byte currentByte = overhead[i];
            System.out.println("add: " + currentByte);
            for (int j = 7; j >= 0; j--) {
                int bit = (currentByte & (0x1 << j)) >> j;
                bit = bit & 0x1;
                System.out.println("Bit: " + bit);
                if (bitCount % 3 == 0) {
                    int red;
                    if (bit == 0) {
                        red = Color.red(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
                    } else {
                        red = Color.red(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
                    }
                    buffer.setPixel(pixelCol, pixelRow, Color.argb(
                            Color.alpha(buffer.getPixel(pixelCol, pixelRow)), red,
                            Color.green(buffer.getPixel(pixelCol, pixelRow)),
                            Color.blue(buffer.getPixel(pixelCol, pixelRow))));
                } else if (bitCount % 3 == 1) {
                    int blue;
                    if (bit == 0) {
                        blue = Color.blue(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
                    } else {
                        blue = Color.blue(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
                    }
                    buffer.setPixel(pixelCol, pixelRow, Color.argb(
                            Color.alpha(buffer.getPixel(pixelCol, pixelRow)),
                            Color.red(buffer.getPixel(pixelCol, pixelRow)),
                            Color.green(buffer.getPixel(pixelCol, pixelRow)), blue));
                } else {
                    int green;
                    if (bit == 0) {
                        green = Color.green(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
                    } else {
                        green = Color.green(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
                    }
                    buffer.setPixel(pixelCol, pixelRow, Color.argb(
                            Color.alpha(buffer.getPixel(pixelCol, pixelRow)),
                            Color.red(buffer.getPixel(pixelCol, pixelRow)), green,
                            Color.blue(buffer.getPixel(pixelCol, pixelRow))));
                    incrementPixel(buffer.getWidth());
                }
                bitCount++;
            }
        }

        overhead = data;
    }
    FileOutputStream out = null;
    try {
        out = new FileOutputStream(tempFile);
        buffer.compress(Bitmap.CompressFormat.PNG, 100, out);
        out.flush();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    incrementPixel(buffer.getWidth());
    return buffer;
}
answered on Stack Overflow Feb 22, 2018 by Satyam Rai

User contributions licensed under CC BY-SA 3.0