java – 将消息存储到R,G,B而不是Alpha

如何更改它以将消息存储到R,G,B的最低有效位.
以下代码仅将消息嵌入Alpha(0~7bit)

embedInteger处理在前32个像素中嵌入消息的长度.

embedByte一个接一个地嵌入你的消息字符.每次调用时,它都以字节形式b [i]作为输入消息中的下一个字符.在那里,它每像素嵌入一位,每字节总共8位.

private void embedMessage(BufferedImage img, byte[] mess) {
    int messageLength = mess.length;
    int imageWidth = img.getWidth(), imageHeight = img.getHeight(),
            imageSize = imageWidth * imageHeight;

    if(messageLength * 8 + 32 > imageSize) {   
        System.out.println("Message is too logn");
        return;
    }
    embedInteger(img, messageLength, 0, 0);
    for(int i=0; i<mess.length; i++){
        embedByte(img, mess[i], i*8+32, 0);

    }
}

private void embedInteger(BufferedImage img, int n, int start, int storageBit) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;
    for(int i=startX; i<maxX && count<32; i++) {
        for(int j=startY; j<maxY && count<32; j++) {
            int rgb = img.getRGB(i, j), bit = getBitValue(n, count); 
            rgb = setBitValue(rgb, storageBit, bit); 
            img.setRGB(i, j, rgb); 
            count++;
        }
    }
}

private void embedByte(BufferedImage img, byte b, int start, int storageBit) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;
    for(int i=startX; i<maxX && count<8; i++) {
        for(int j=startY; j<maxY && count<8; j++) {
            int rgb = img.getRGB(i, j), bit = getBitValue(b, count); 
            rgb = setBitValue(rgb, storageBit, bit);
            img.setRGB(i, j, rgb);
            count++;
        }
    }
}

private int getBitValue(int n, int location) { //n=messageLength, location=count

    int v = n & (int) Math.round(Math.pow(2, location));
    return v==0?0:1;
}

private int setBitValue(int n, int location, int bit) { 
    int toggle = (int) Math.pow(2, location), bv = getBitValue(n, location); 
    if(bv == bit)

        return n;
    if(bv == 0 && bit == 1){
        n |= toggle;
        System.out.println("n{toggle: "+n);
    }else if(bv == 1 && bit == 0){
        n ^= toggle;
    }
    return n;

}

解决方法:

您想要在embedMessage方法中更改以下行.

embedInteger(img, messageLength, 0, 0);
embedByte(img, mess[i], i*8+32, 0);

最后一个输入(在这种情况下为0)决定了嵌入位的RGBA像素值的位位置.下面的图片来自您找到代码的网站,它显示了像素值的位顺序.

因此,对于R分量的LSB,您需要8,G,16和B 24.

嵌入多个颜色组件

很多文献报道了RGB中的隐写术. RGBA非常相似,但具有透明度的额外信息. Wikipedia是一个阅读的好地方.实际上,不同之处在于RGB有3个分量,每个像素总共24位,而RGBA有4个分量,每个像素32位.通过嵌入多个组件,您可以将隐藏容量提高3或4倍.

如果要将一个字节嵌入RGB,则需要2和2/3像素(3 3 2个分量).但对于RGBA,您只需要两个像素(4个4个分量).我将演示如何扩展代码以隐藏RGBA中的单个消息,因为在这种情况下它更简单.如上所述,这将使您的隐藏容量翻两番.为了实现这一目标,代码中发生了很多变化,但可以归结为:

> Ditch storageBit因为不再需要了.
>您可以将每个字节嵌入两个像素.在第一个像素中,您在第一个像素的A,B,G和R分量的LSB中嵌入前4位,在第二个像素的LSB分量中嵌入最后4位.

要应用更改,只需使用网站提供的代码开始清理,并完全替换以下方法进行编码和解码过程.

编码

private void openImage() {
   java.io.File f = showFileDialog(true);
   try {   
      sourceImage = ImageIO.read(f);
      sourceImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = sourceImage.createGraphics();
      g.drawImage(ImageIO.read(f), 0, 0, null);
      g.dispose();
      JLabel l = new JLabel(new ImageIcon(sourceImage));
      originalPane.getViewport().add(l);
      this.validate();
      } catch(Exception ex) { ex.printStackTrace(); }
   }

private void embedMessage(BufferedImage img, String mess) {
   int messageLength = mess.length();

   int imageWidth = img.getWidth(), imageHeight = img.getHeight(),
      imageSize = imageWidth * imageHeight;
   if(messageLength * 2 + 8 > imageSize) {
      JOptionPane.showMessageDialog(this, "Message is too long for the chosen image",
         "Message too long!", JOptionPane.ERROR_MESSAGE);
      return;
      }
   embedInteger(img, messageLength, 0);

   byte b[] = mess.getBytes();
   for(int i=0; i<b.length; i++)
      embedByte(img, b[i], i*2+8);
   }

private void embedInteger(BufferedImage img, int n, int start) {
   int maxX = img.getWidth(), maxY = img.getHeight(), 
      startX = start/maxY, startY = start - startX*maxY, count=0;
   for(int i=startX; i<maxX && count<32; i++) {
      for(int j=startY; j<maxY && count<32; j++) {
         int rgb = img.getRGB(i, j), bit = getBitValue(n, count);
         rgb = setBitValue(rgb, 0, bit);
         bit = getBitValue(n, count+1); rgb = setBitValue(rgb, 8, bit);
         bit = getBitValue(n, count+2); rgb = setBitValue(rgb, 16, bit);
         bit = getBitValue(n, count+3); rgb = setBitValue(rgb, 24, bit);
         img.setRGB(i, j, rgb); 
         count = count+4;
         }
      }
   }

private void embedByte(BufferedImage img, byte b, int start) {
   int maxX = img.getWidth(), maxY = img.getHeight(), 
      startX = start/maxY, startY = start - startX*maxY, count=0;
   for(int i=startX; i<maxX && count<8; i++) {
      for(int j=startY; j<maxY && count<8; j++) {
         if(j==maxY-1){
            startY = 0;
            }
         int rgb = img.getRGB(i, j), bit = getBitValue(b, count);
         rgb = setBitValue(rgb, 0, bit);
         bit = getBitValue(b, count+1); rgb = setBitValue(rgb, 8, bit);
         bit = getBitValue(b, count+2); rgb = setBitValue(rgb, 16, bit);
         bit = getBitValue(b, count+3); rgb = setBitValue(rgb, 24, bit);
         img.setRGB(i, j, rgb);
         count = count+4;
         }
      }
   }

解码

private void openImage() {
   java.io.File f = showFileDialog(true);
   try {   
      image = ImageIO.read(f);
      image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = image.createGraphics();
      g.drawImage(ImageIO.read(f), 0, 0, null);
      g.dispose();
      JLabel l = new JLabel(new ImageIcon(image));
      imagePane.getViewport().add(l);
      this.validate();
      } catch(Exception ex) { ex.printStackTrace(); }
   }

private void decodeMessage() {
   int len = extractInteger(image, 0);
   byte b[] = new byte[len];
   for(int i=0; i<len; i++)
      b[i] = extractByte(image, i*2+8);
   message.setText(new String(b));
   }

private int extractInteger(BufferedImage img, int start) {
   int maxX = img.getWidth(), maxY = img.getHeight(), 
      startX = start/maxY, startY = start - startX*maxY, count=0;
   int length = 0;
   for(int i=startX; i<maxX && count<32; i++) {
      for(int j=startY; j<maxY && count<32; j++) {
         int rgb = img.getRGB(i, j), bit = getBitValue(rgb, 0);
         length = setBitValue(length, count, bit);
     bit = getBitValue(rgb, 8); length = setBitValue(length, count+1, bit);
         bit = getBitValue(rgb, 16); length = setBitValue(length, count+2, bit);
         bit = getBitValue(rgb, 24); length = setBitValue(length, count+3, bit);
         count = count+4;
         }
      }
   return length;
   }

private byte extractByte(BufferedImage img, int start) {
   int maxX = img.getWidth(), maxY = img.getHeight(), 
      startX = start/maxY, startY = start - startX*maxY, count=0;
   byte b = 0;
   for(int i=startX; i<maxX && count<8; i++) {
      for(int j=startY; j<maxY && count<8; j++) {
         if(j==maxY-1){
            startY = 0;
            }
         int rgb = img.getRGB(i, j), bit = getBitValue(rgb, 0);
         b = (byte)setBitValue(b, count, bit);
         bit = getBitValue(rgb, 8); b = (byte)setBitValue(b, count+1, bit);
     bit = getBitValue(rgb, 16); b = (byte)setBitValue(b, count+2, bit);
     bit = getBitValue(rgb, 24); b = (byte)setBitValue(b, count+3, bit);
         count = count+4;
         }
      }
   return b;
   }

在每个颜色组件中嵌入不同的秘密

我已经修改了代码,所以这次你可以选择你想要隐藏GUI的秘密的颜色组件.这实际上优于上面隐藏在所有RGBA中的版本.在这里,您具有隐藏消息的颜色组件的多功能性,如果您有一个非常长的消息,您可以将它分成四个部分.为此,我在代码的各个部分进行了以下更改:

>根据您是否分别选择了A,R,G或B,将storageBit的值内部更改为0,8,16或24.
>此选项在GUI上进行,因此您不必每次都重新编译不同颜色组件的代码.

要应用更改,请从网站提供的代码开始清除,并完全替换以下方法,以用于编码和解码过程.

public class EmbedMessage extends JFrame implements ActionListener
{
JButton open = new JButton("Open"), embed = new JButton("Embed"),
   save = new JButton("Save into new file"), reset = new JButton("Reset");
String[] rgbaList = { "B", "G", "R", "A" };
JComboBox<String> chooseRGBA = new JComboBox<>(rgbaList);
JTextArea message = new JTextArea(10,3);
BufferedImage sourceImage = null, embeddedImage = null;
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JScrollPane originalPane = new JScrollPane(),
   embeddedPane = new JScrollPane();

private void assembleInterface() {
   JPanel p = new JPanel(new FlowLayout());
   p.add(open);
   p.add(chooseRGBA);
   p.add(embed);
   p.add(save);   
   p.add(reset);
   this.getContentPane().add(p, BorderLayout.SOUTH);
   open.addActionListener(this);
   embed.addActionListener(this);
   save.addActionListener(this);   
   reset.addActionListener(this);
   open.setMnemonic('O');
   embed.setMnemonic('E');
   save.setMnemonic('S');
   reset.setMnemonic('R');

   p = new JPanel(new GridLayout(1,1));
   p.add(new JScrollPane(message));
   message.setFont(new Font("Arial",Font.BOLD,20));
   p.setBorder(BorderFactory.createTitledBorder("Message to be embedded"));
   this.getContentPane().add(p, BorderLayout.NORTH);

   sp.setLeftComponent(originalPane);
   sp.setRightComponent(embeddedPane);
   originalPane.setBorder(BorderFactory.createTitledBorder("Original Image"));
   embeddedPane.setBorder(BorderFactory.createTitledBorder("Steganographed Image"));
   this.getContentPane().add(sp, BorderLayout.CENTER);
   }

public void actionPerformed(ActionEvent ae) {
   Object o = ae.getSource();
   if(o == open)
      openImage();
   else if(o == embed){
      int rgbaChoice = chooseRGBA.getSelectedIndex(), sb = 0;
      if(rgbaChoice == 0)
         sb = 24;
      else if(rgbaChoice == 1)
         sb = 16;
      else if(rgbaChoice == 2)
         sb = 8;
      else if(rgbaChoice == 3)
         sb = 0;
      embedMessage(sb);
      }
   else if(o == save) 
      saveImage();
   else if(o == reset) 
      resetInterface();
   }

private void openImage() {
   java.io.File f = showFileDialog(true);
   try {   
      sourceImage = ImageIO.read(f);
      sourceImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = sourceImage.createGraphics();
      g.drawImage(ImageIO.read(f), 0, 0, null);
      g.dispose();
      JLabel l = new JLabel(new ImageIcon(sourceImage));
      originalPane.getViewport().add(l);
      this.validate();
      } catch(Exception ex) { ex.printStackTrace(); }
   }

private void embedMessage(int storageBit) {
   String mess = message.getText();
   embeddedImage = sourceImage.getSubimage(0,0,
      sourceImage.getWidth(),sourceImage.getHeight());
   embedMessage(embeddedImage, mess, storageBit);
   JLabel l = new JLabel(new ImageIcon(embeddedImage));
   embeddedPane.getViewport().add(l);
   this.validate();
   }

private void embedMessage(BufferedImage img, String mess, int storageBit) {
   int messageLength = mess.length();

   int imageWidth = img.getWidth(), imageHeight = img.getHeight(),
      imageSize = imageWidth * imageHeight;
   if(messageLength * 8 + 32 > imageSize) {
      JOptionPane.showMessageDialog(this, "Message is too long for the chosen image",
         "Message too long!", JOptionPane.ERROR_MESSAGE);
      return;
      }
   embedInteger(img, messageLength, 0, storageBit);

   byte b[] = mess.getBytes();
   for(int i=0; i<b.length; i++)
      embedByte(img, b[i], i*8+32, storageBit);
   }

解码

public class DecodeMessage extends JFrame implements ActionListener
{
JButton open = new JButton("Open"), decode = new JButton("Decode"),
   reset = new JButton("Reset");
String[] rgbaList = { "B", "G", "R", "A" };
JComboBox<String> chooseRGBA = new JComboBox<>(rgbaList);
JTextArea message = new JTextArea(10,3);
BufferedImage image = null;
JScrollPane imagePane = new JScrollPane();

private void assembleInterface() {
   JPanel p = new JPanel(new FlowLayout());
   p.add(open);
   p.add(chooseRGBA);
   p.add(decode);
   p.add(reset);
   this.getContentPane().add(p, BorderLayout.NORTH);
   open.addActionListener(this);
   decode.addActionListener(this);
   reset.addActionListener(this);
   open.setMnemonic('O');
   decode.setMnemonic('D');
   reset.setMnemonic('R');

   p = new JPanel(new GridLayout(1,1));
   p.add(new JScrollPane(message));
   message.setFont(new Font("Arial",Font.BOLD,20));
   p.setBorder(BorderFactory.createTitledBorder("Decoded message"));
   message.setEditable(false);
   this.getContentPane().add(p, BorderLayout.SOUTH);

   imagePane.setBorder(BorderFactory.createTitledBorder("Steganographed Image"));
   this.getContentPane().add(imagePane, BorderLayout.CENTER);
   }

public void actionPerformed(ActionEvent ae) {
   Object o = ae.getSource();
   if(o == open)
      openImage();
   else if(o == decode){
      int rgbaChoice = chooseRGBA.getSelectedIndex(), sb = 0;
      if(rgbaChoice == 0)
         sb = 24;
      else if(rgbaChoice == 1)
         sb = 16;
      else if(rgbaChoice == 2)
         sb = 8;
      else if(rgbaChoice == 3)
         sb = 0;
      decodeMessage(sb);
      }
   else if(o == reset) 
      resetInterface();
   }

private void openImage() {
   java.io.File f = showFileDialog(true);
   try {   
      image = ImageIO.read(f);
      image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = image.createGraphics();
      g.drawImage(ImageIO.read(f), 0, 0, null);
      g.dispose();
      JLabel l = new JLabel(new ImageIcon(image));
      imagePane.getViewport().add(l);
      this.validate();
      } catch(Exception ex) { ex.printStackTrace(); }
   }

private void decodeMessage(int storageBit) {
   int len = extractInteger(image, 0, storageBit);
   byte b[] = new byte[len];
   for(int i=0; i<len; i++)
      b[i] = extractByte(image, i*8+32, storageBit);
   message.setText(new String(b));
   }

private byte extractByte(BufferedImage img, int start, int storageBit) {
   int maxX = img.getWidth(), maxY = img.getHeight(), 
      startX = start/maxY, startY = start - startX*maxY, count=0;
   byte b = 0;
   for(int i=startX; i<maxX && count<8; i++) {
      for(int j=startY; j<maxY && count<8; j++) {
         if(j==maxY-1){
            startY = 0;
            }
         int rgb = img.getRGB(i, j), bit = getBitValue(rgb, storageBit);
         b = (byte)setBitValue(b, count, bit);
         count++;
         }
      }
   return b;
   }
上一篇:elementUI el-dialog 解决embed标签无法实时更新预览PDF文件


下一篇:如何使用tkinter在python中嵌入python解释器框架?