无法从java中修改的Byte数组生成Image

时间:2018-04-14 16:33:37

标签: java

在我的代码中,我读取图像将其转换为字节数组并使用某些逻辑修改该字节数组并尝试从该修改后的字节数组生成图像,但我无法从该代码生成图像

我的代码示例:

//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") );

在此代码中,我在第3步中遇到错误:

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)

2 个答案:

答案 0 :(得分:1)

这是一种令人印象深刻的迂回操作方式。没有正当理由使用字符串。我建议您使用按位运算符,或使用BitSet

以数学方式迭代比特:

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;

使用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];

您可能会注意到,由于BitSet.valueOf采用了一个字节数组,因此继续创建新的BitSet会很浪费。相反,您可以只执行BitSet.valueOf(bytes)一次,并遍历该单个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();

...然而

PNG图像(通常)是压缩的。这意味着这些位不直接对应于像素。修改这些位会产生无效的压缩数据块,这就是为什么尝试使用ImageIO.read读取它会失败并返回null。

如果你想要字节,你可以直接操作,从原始BufferedImage获取它们,而不是从PNG表示:

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

如果您花时间为变量提供有意义的名称,那么其他人会更容易帮助您。 tempuv以及zx是神秘而毫无意义的。更好的名字是:

  • temp_string→allByteValues
  • uv→bitsOfByte
  • tempStr→newBits
  • zx→bitIndex(或只是一个典型的二级索引变量,如j
  • temp→bit

当您完成修改字节后,您仍然拥有原始图像数据,而不是PNG表示,因此您无法从这些字节创建ByteArrayInputStream并将它们传递给ImageIO.read。尝试将这些字节作为PNG表示传递将始终失败。

相反,使用像素数据覆盖您的图像:

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"));

答案 1 :(得分:0)

正如documentation中所述,如果write方法的任何参数为空,它将抛出IllegalArgumentException

你这样打电话:

ImageIO.write(bImage2, "png", new File("output.png") );

唯一可以为null的参数是bImage2

请检查它是否真的null