【问题标题】:How to convert image byte array into a bitmap after altering with the byte array使用字节数组更改后如何将图像字节数组转换为位图
【发布时间】:2018-08-01 10:58:56
【问题描述】:

我正在尝试在 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的情况下是无效的。

【问题讨论】:

  • 在不知道get_byte_data() 做什么、bit_conversion() 做什么或encode_text() 做什么的情况下,无法为您提供帮助。请记住,您传递给 decodeByteArray()byte[] 需要采用可识别且受支持的图像格式(例如 PNG、JPEG、WebP)。
  • 好的,我会放代码

标签: java android arrays bitmap steganography


【解决方案1】:

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

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

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

【讨论】:

  • 实际上,我需要更改字节,所以有什么方法可以在不破坏字节的情况下更改字节。就像我上面提到的 Java 一样,同样的算法给了我正确的输出。
  • @SatyamRai:“我需要更改字节”——为什么? “所以有什么方法可以在不破坏字节的情况下改变它们”——确保在完成后得到一个有效的 JPEG。我不知道你打算怎么做。 “就像我上面提到的 Java 一样,相同的算法给了我正确的输出”——BufferedImage 不是 JPEG。
  • 由于我正在实现隐写术,所以我想在图像的每个字节中逐位编码消息。那么除了Bitmap之外,Android中的BufferedImage还有其他选择吗?
  • @SatyamRai:“因为我正在实施隐写术,所以我想在图像的每个字节中逐位编码消息”——调整算法以逐像素编码消息基础。然后,将图像保存为 PNG,否则如果您编码为 JPEG,您的编码数据将会丢失。或者,如果您确定需要 JPEG 输出,请使用 NDK 和 libjpeg 直接处理 JPEG 图像。已有适用于 Android 的开源隐写术代码示例;也许可以向那些寻求想法。
  • @SatyamRai 这是您正在寻找的答案。你可能不喜欢它,但这就是现实。直接修改图像文件字节的隐写术适用于 bmp 等格式,其中字节表示原始数据。压缩格式绝对不是这种情况。如果您想修改像素本身,将修改后的图像保存为无损格式的建议同样重要。
【解决方案2】:

我终于弄明白了,正如上面评论中提到的,解决方案是逐个像素地解决它。所以我取了一个像素,将数据一点一点地放入它的 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-14
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 2018-05-06
    • 2016-06-11
    相关资源
    最近更新 更多