有损压缩中的隐写术(JAVA)

有损压缩中的隐写术(JAVA),java,image,compression,jpeg,steganography,Java,Image,Compression,Jpeg,Steganography,我用java对jpeg图像中的数据进行编码。我正在将文本转换为二进制形式,并将其插入(0,0)到(宽度、高度)之间每个像素中RGB的LSB(取决于用户选择的。1,2,3,4) 外部: 对于(int i=0;i

我用java对jpeg图像中的数据进行编码。我正在将文本转换为二进制形式,并将其插入(0,0)到(宽度、高度)之间每个像素中RGB的LSB(取决于用户选择的。1,2,3,4)

外部:
对于(int i=0;i
目前,我写它作为一个png,它工作得很好,但我希望在jpeg的这一点。我成功地获得了png格式的数据。但正如所料,在jpeg中失败了

我能够解码写入的图像中的隐藏位,并在选择正确LSB的情况下看到消息

我目前正在阅读有关JPEG隐写术的文章,但还没有完全了解该如何开始。我看过算法,也没帮到我

我看到一段代码没有找到任何主类

我必须在我的申请中调用它吗?修改它?我将如何解码


这是我看到的一个例子。

jpeg使用有损压缩方法来实现较小的文件大小。不幸的是,这种方法直接影响(某些)像素的值,从而破坏了嵌入信息的方式。您需要以无损格式保存文件以避免此问题,例如bmp或png

Jpeg隐写术的编码稍微复杂一些,但概念很简单。您需要编写一个jpeg编码器,或者使用现有的编码器。您链接到的代码实际上是一个编码器,只需稍作修改,就可以在项目中使用它

如果你想理解代码,你可以阅读维基百科上的文章。我将简要总结其一些关键步骤

  • 将图像分割为8x8块
  • 使用离散余弦变换(DCT)来获得浮点DCT系数,并将其量化为整数
  • 使用哈夫曼编码和游程编码将量化系数存储到文件中
第二步的量化是有损位,但随后的一切都是无损的。基本上,从第二步获得量化系数,用你的隐写算法修改它们,然后继续第三步

关于链接代码的实际修改。
Compress
方法是将rgb图像存储到文件中所需调用的方法。它负责写入头数据和压缩系数。您只需要在
writecompressedata
方法中添加一些代码。现在它所做的是在每个8x8图像块上循环,应用dct并量化系数,这些系数存储在
dctArray3
中。然后将这些数据压缩并写入文件。在调用
Huf.HuffmanBlockEncoder
之前,您必须通过修改
dctArray3
进行干预

例如,假设您有一个秘密的字节数组,称为
message
,您希望在特定系数的lsb中每8x8块嵌入一位

public void WriteCompressedData(BufferedOutputStream outStream, byte[] message) {
    byte currentByte;
    int nBytes = message.length;
    int iByte = 0;
    int iBit = 7;
    if (nBytes > 0) {
        currentByte = message[0];
    } else {
        currentByte = (byte) 0;
    }
    // Original method code up until the following line
    dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);
    // ******************** our stuff *******************
    if (iByte < nBytes) {
        int bit = (currentByte >> iBit) & 1;
        iBit--;
        if (iBit == -1) {
            iBit = 7;
            iByte++;
            if (iByte < nBytes) {
                currentByte = message[iByte];
            }
        }
        dctArray3[23] = (dctArray3[23] & 0xfffffffe) | bit;
    }
    // **************************************************
    Huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp], JpegObj.DCtableNumber[comp], JpegObj.ACtableNumber[comp]);
    ...
}

这个周末晚些时候我会核对你的答案。感谢您的回答:)我纠正了编码序列逻辑中的一个错误(应该是
if(iBit==-1)
而不是0),并添加了一个解码器示例。我是否可以使用我的方法对图像进行编码,调用原始JPEG编码器,让它写入图像。然后我颠倒了它的过程,最后,我应用了我的解码过程。它可行吗?用你的方法对图像进行编码是什么意思?你的意思是将信息嵌入像素,然后保存为jpeg格式吗?就像前面指出的那样,你不能将数据嵌入像素,然后将其编码为jpeg格式。Jpeg文件通过存储DCT系数实现压缩。如上所述,这是一个无损过程。你必须处理文件格式给你的信息。为了无损存储像素,需要使用不同的格式。
public void WriteCompressedData(BufferedOutputStream outStream, byte[] message) {
    byte currentByte;
    int nBytes = message.length;
    int iByte = 0;
    int iBit = 7;
    if (nBytes > 0) {
        currentByte = message[0];
    } else {
        currentByte = (byte) 0;
    }
    // Original method code up until the following line
    dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);
    // ******************** our stuff *******************
    if (iByte < nBytes) {
        int bit = (currentByte >> iBit) & 1;
        iBit--;
        if (iBit == -1) {
            iBit = 7;
            iByte++;
            if (iByte < nBytes) {
                currentByte = message[iByte];
            }
        }
        dctArray3[23] = (dctArray3[23] & 0xfffffffe) | bit;
    }
    // **************************************************
    Huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp], JpegObj.DCtableNumber[comp], JpegObj.ACtableNumber[comp]);
    ...
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import ortega.HuffmanDecode;

public class Extract {
    private static byte[] deZigZag = {
            0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31,
            40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61,
            35, 36, 48, 49, 57, 58, 62, 63 };

    private static int[] extract(InputStream fis, int flength) throws IOException {
        byte[] carrier = new byte[flength];
        fis.read(carrier);
        HuffmanDecode hd = new HuffmanDecode(carrier);
        int[] coeff = hd.decode();
        return coeff;
    }

    public static void main(String[] args) {
        // run with argument the stego jpeg filename
        try {
            File f = new File(args[0]);
            FileInputStream fis = new FileInputStream(f);
            int[] coeff = extract(fis, (int) f.length());

            int idx = deZigZag[23];
            // The coeff array has all of the DCT coefficients in one big
            // array, so that the first 64 elements are the coefficients 
            // from the first block, the next 64 from the second and so on.
            //
            // idx is the position of the embedding DCT coefficient.
            // You can start with that and extract its lsb, then increment
            // by 64 to extract the next bit from the next "block" and so on.
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}