如何在使用字节数组进行更改后将图像字节数组转换为位图

时间:2018-02-21 18:33:25

标签: java android arrays bitmap steganography

我正在尝试在Android中实现隐写术,我已经实现了代码来逐位编码图像。

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;
}

但在将数据编码到图像后,我无法形成位图。

我在java中实现了相同的算法并且工作正常:

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;
}

所以有人可以帮我弄清楚为什么在android的情况下字节数组是无效的。

2 个答案:

答案 0 :(得分:1)

您从byte[]的JPEG数据开始。然后,您可以修改该数据,半随机更改位,而不考虑JPEG数据格式。然后,您尝试解码已修改的byte[]。毫不奇怪,BitmapFactory无法对其进行解码,因为它不再是有效的图像格式。

我最好的猜测是你认为byte[]是ARGB格式的原始像素。

如果是这种情况,请使用getPixel()上的setPixel()Bitmap等方法修改像素,并跳过位图编码和解码步骤。

答案 1 :(得分:0)

我终于能够弄明白了,正如上面评论中提到的,解决方案是逐像素地解决它。所以我拿了一个像素并将数据一点一点地放在它的rgb值中。所以这是代码:

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;
}