将消息存储到R,G,B而不是Alpha [英] Storing message into R,G,B instead of Alpha

查看:251
本文介绍了将消息存储到R,G,B而不是Alpha的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How to change it to store message into least significant bit of R,G,B. The code below only embed message into Alpha (0~7bit)

embedInteger 处理将消息长度嵌入到前32个像素。

embedInteger deals with embedding the length of the message in the first 32 pixels.

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

embedByte embeds your message characters, one by one. Every time it is called upon, it takes as an input the next character in your message in byte form, b[i]. There, it embeds one bit per pixel, for a total of 8 bits per byte.

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 方法中的以下行。

You want to change the following lines in the embedMessage method.

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

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

The last input, which is 0 in this case, determines the bit location of the RGBA pixel value you will embed your bit. The following image, which is taken from the website you found the code, shows you the bit order for the pixel value.

因此,对于R组件的LSB,您需要8,G,16和B 24。

So, for the LSB of the R component, you want 8, for the G, 16 and for B 24.

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

A lot of the literature report steganography in RGB. RGBA is very similar, but with the extra information of transparency. Wikipedia is as good a place to read up on that. Effectively, the difference is that RGB has 3 components with 24 bits per pixel in total, while RGBA has 4 components with 32 bits per pixel. By embedding into multiple components, you can increase your hiding capacity by a factor of 3 or 4.

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

If you want to embed a byte into RGB, you will need 2 and 2/3 pixels (3+3+2 components). But for RGBA you only need two pixels (4+4 components). I will demonstrate how to extend your code to hide a single message in RGBA, as it is simpler in this case. As stated above, this will quadruple your hiding capacity. There are quite a few changes that take place all over the code to make this possible, but they can be boiled down to:


  • Ditch storageBit因为不再需要了。

  • 您可以将每个字节嵌入两个像素中。在第一个像素中,您在第一个像素的A,B,G和R分量的LSB中嵌入前4位,在第二个像素的LSB分量中嵌入最后4位。

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

To apply the changes, just start clean with the code as provided in the website and substitute fully the following methods for both the encoding and decoding process.

编码

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中的上述版本。在这里,您具有隐藏消息的颜色组件的多功能性,如果您有一个非常长的消息,您可以将它分成四个部分。为此,我在代码的各个部分进行了以下更改:

Embedding different secrets in each colour component

I have modified the code so this time you can choose in which colour component you want to hide your secret from the GUI. This is is effectively superior to the version above hiding in all RGBA. Here, you have the versatility in which colour component to hide your message and if you have a really long one, you can split it in four parts. To do this I made the following changes in various part of the code:


  • 更改 storageBit的值内部为0,8,16或24,具体取决于您是否分别选择了A,R,G或B.

  • 此选项在GUI上进行,因此您不必每次都必须重新编译不同颜色组件的代码。

  • Change the value of storageBit internally to 0, 8, 16 or 24 depending on whether you have chosen A, R, G or B respectively.
  • This choice is made on the GUI so you don't have to recompile the code for different colour components every time.

要应用更改,请从代码中开始清理,如网站并完全替换以下方法,用于编码和解码过程。

To apply the changes, start clean from the code as provided in the website and substitute wholly the following methods, for both the encoding and decoding processes.

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

这篇关于将消息存储到R,G,B而不是Alpha的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆