Java 我正在读一个图像并改变它。但这些更改不会被保存

Java 我正在读一个图像并改变它。但这些更改不会被保存,java,arrays,byte,bufferedimage,steganography,Java,Arrays,Byte,Bufferedimage,Steganography,我正在尝试实现一种隐写术。 我正在读取图像a.jpeg,并通过从偏移量50开始更改其连续7个字节的最低有效位,在其中插入一个字节。 这是成功的,因为当我打印字节时,最后的位会相应地改变。 然后我将其保存为ao.jpeg。但是,当我从50读取字节值时,它们与我保存的字节值不同。 这是我的密码 public static void main(String[] args) throws IOException { BufferedImage inputImage = ImageIO.r

我正在尝试实现一种隐写术。 我正在读取图像a.jpeg,并通过从偏移量50开始更改其连续7个字节的最低有效位,在其中插入一个字节。 这是成功的,因为当我打印字节时,最后的位会相应地改变。 然后我将其保存为ao.jpeg。但是,当我从50读取字节值时,它们与我保存的字节值不同。 这是我的密码

public static void main(String[] args) throws IOException {
        BufferedImage inputImage = ImageIO.read(new File("a.jpeg"));
        int offset=50;
        byte data = 7;
        byte[] image = get_byte_data(inputImage);//function converts bufferedimage to byte array
        //add data at end of each byte starting from offset
        System.out.println("bytes altered are :");
        for(int bit=7; bit>=0; --bit, ++offset)//for each bit of data
            {
            int b = (data >>> bit) & 1;
            image[offset] = (byte)((image[offset] & 0xFE) | b );
            String s1 = String.format("%8s", Integer.toBinaryString(image[offset] & 0xFF)).replace(' ', '0');
            System.out.println(s1);
            }
        //write changed image to ao.jpeg
        BufferedImage outputImage = ImageIO.read(new ByteArrayInputStream(image)); 
        File outputfile = new File("ao.jpeg");
        ImageIO.write(outputImage,"jpeg",outputfile);
        //read data from ao.jpeg
        System.out.println("bytes from encoded image are :");
        byte result=0;
        offset=50;
        BufferedImage oImage = ImageIO.read(new File("aoc.jpeg"));
        byte[] image1 = get_byte_data(oImage);//function converts bufferedimage to byte array
            for(int i=0; i<8; i++, ++offset)
             {
             result = (byte)((result << 1) | (image1[offset] & 1));
             String s1 = String.format("%8s", Integer.toBinaryString(image1[offset] & 0xFF)).replace(' ', '0');
             System.out.println(s1);
             }
            System.out.println("recovered data is :");
            System.out.print(result);
        }
正如Konstantin V.Salikhov所建议的那样,我尝试了不同的文件格式gif,效果不错。
但是有什么方法可以使用jpeg吗?

jpeg是一种有损存储机制。这意味着不需要或甚至不希望将每个字节都精确地表示为原始字节。事实上,这就是关键所在,它牺牲了小的缺陷,以节省大量空间。如果您需要字节完美存储,您必须找到并选择另一种格式,如GIF、PNG或某种风格的BMP


正如下面所指出的,从技术上讲,创建无损JPEG是可能的,但这是一个后期添加,不完全支持,特别是Java本身不支持它。有关更多信息,请参阅。

JPEG是一种有损存储机制。这意味着不需要或甚至不希望将每个字节都精确地表示为原始字节。事实上,这就是关键所在,它牺牲了小的缺陷,以节省大量空间。如果您需要字节完美存储,您必须找到并选择另一种格式,如GIF、PNG或某种风格的BMP

正如下面所指出的,从技术上讲,创建无损JPEG是可能的,但这是一个后期添加,不完全支持,特别是Java本身不支持它。有关更多信息,请参阅。

您的方法失败的原因 正如Salinkov所说,jpeg格式会导致数据压缩。要总结您所做的工作:

您在字节数组中加载了图像数据。 您修改了一些字节。 您将字节数组作为映像加载。 您以jpeg格式保存了此图像,这将导致重新压缩。 这就是你的方法失败的地方。无损格式不会产生这些问题,这就是gif工作的原因。或png、bmp等

你能用你的方法处理jpeg吗? Weeeell,不,不是真的。首先,我们需要了解jpeg图像包含的数据类型

简而言之,单个字节与图像中的实际像素不对应

说来话长,就是将图像分割成8x8阵列,然后进行DCT以获得频率系数。经过量化步骤后,其中许多将变为0,尤其是DCT阵列右下角的高频系数-。这是jpeg的有损步骤。您可以牺牲更高的频率系数来换取一些可容忍的图像失真信息损失。现在,您保存的是非零系数,基于它们在矩阵中的位置,即0、0、-26、0、1、-3等。这可以通过哈夫曼编码进一步压缩。顺便说一下,更改任何一个频率分量都会影响所有64个像素

那么jpeg隐写术通常是如何完成的呢?它主要遵循jpeg编码过程:

在8x8阵列中分割图像。 对每个8x8阵列进行DCT并量化系数。 现在我们已经获得了量化的DCT系数,我们暂时停止jpeg编码过程

通过改变量化系数的值来应用一些隐写算法

哈夫曼压缩系数,并使用这些修改后的DCT系数继续jpeg编码过程的其余部分

为什么你的方法失败了 正如Salinkov所说,jpeg格式会导致数据压缩。要总结您所做的工作:

您在字节数组中加载了图像数据。 您修改了一些字节。 您将字节数组作为映像加载。 您以jpeg格式保存了此图像,这将导致重新压缩。 这就是你的方法失败的地方。无损格式不会产生这些问题,这就是gif工作的原因。或png、bmp等

你能用你的方法处理jpeg吗? Weeeell,不,不是真的。首先,我们需要了解jpeg图像包含的数据类型

简而言之,单个字节与图像中的实际像素不对应

说来话长,就是将图像分割成8x8阵列,然后进行DCT以获得频率系数。经过量化步骤后,其中许多将变为0,尤其是DCT阵列右下角的高频系数-。这是jpeg的有损步骤。您可以牺牲更高的频率系数来换取一些可容忍的图像失真信息损失。现在,您保存的是非零系数,基于它们在矩阵中的位置,即0、0、-26、0、1、-3等。这可以通过哈夫曼编码进一步压缩。顺便说一下,更改任何一个频率分量都会影响所有64个像素

那么jpeg隐写术通常是如何完成的呢?它主要遵循jpeg编码过程 :

在8x8阵列中分割图像。 对每个8x8阵列进行DCT并量化系数。 现在我们已经获得了量化的DCT系数,我们暂时停止jpeg编码过程

通过改变量化系数的值来应用一些隐写算法

哈夫曼压缩系数,并使用这些修改后的DCT系数继续jpeg编码过程的其余部分


这可能是因为JPEG有损压缩?我会尝试其他格式和您建议的后期结果解决方案??更重要的一点。JPEG的基本原理是不准确地保留最低位信息,这就是它压缩效果如此好的原因。出于同样的原因,更改更重要的位将不起作用。Jpeg压缩可以有效地更改像素的值,有时更改值为1。那么,如果您有0001111,它被更改为00100000,该怎么办?您丢失了在第5个LSB中编码的信息。可能是因为JPEG有损压缩?我将尝试其他格式并发布您建议的结果解决方案??更改更重要的位。JPEG的基本原理是不准确地保留最低位信息,这就是它压缩效果如此好的原因。出于同样的原因,更改更重要的位将不起作用。Jpeg压缩可以有效地更改像素的值,有时更改值为1。那么,如果您有0001111,它被更改为00100000,该怎么办?你已经丢失了在第五个LSB中编码的信息。实际上,如果OP想如此严格地使用JPEG,可以进行无损的JPEG修改。GIF只支持颜色索引模式,因此即使更改一个位,也会使像素更改为任何随机颜色,可能包括透明颜色。我们的专栏私下里说,嘿,它是用gif制作的,但肯定有一整套自己的可视艺术品。谢谢你的回复。我不想用jpeg,我只是想知道这是否可能。当我使用gif时,图像没有明显的变化,这可能是因为我只更改了几个字节。实际上,如果OP想如此努力地使用JPEG,就会进行无损的JPEG修改。GIF只支持颜色索引模式,因此即使更改一个位,也会使像素更改为任何随机颜色,可能包括透明颜色。我们的OP私下说,嘿,它与gif一起工作,但肯定有一整套自己的可见人工制品。谢谢你的回复。我不想使用jpeg,我只是想知道这是否可行。当我使用gif时,图像没有明显的变化,这可能是因为我只更改了几个字节。
bytes altered are :
00010100
00011100
00011010
00011110
00011110
00011101
00011011
00011101
bytes from encoded image are :
00011110
00011101
00011010
00011100
00011100
00100000
00100100
00101110
recovered data is :
64