Сохранение сообщения в R,G,B вместо Альфы

Как изменить его, чтобы сохранить сообщение в младшем значащем бите R,G,B. Код ниже только для встраивания сообщения в Альфа (0~7 бит)

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;

}

1 ответ

Решение

Вы хотите изменить следующие строки в embedMessage метод.

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

Последний вход, который в данном случае равен 0, определяет местоположение бита значения пикселя RGBA, в которое вы будете вставлять свой бит. На следующем изображении, которое взято с сайта, на котором вы нашли код, показан порядок следования битов для значения пикселя.

Итак, для LSB компонента R вы хотите 8, для G, 16 и для B 24.

Встраивание в несколько цветовых компонентов

Много литературы посвящено стеганографии в РГБ. RGBA очень похож, но с дополнительной информацией о прозрачности. Википедия - также хорошее место, чтобы прочитать об этом. Фактически, разница состоит в том, что RGB имеет 3 компонента с общим количеством битов 24 на пиксель, а RGBA имеет 4 компонента с 32 битами на пиксель. Встраивая в несколько компонентов, вы можете увеличить укрывистость в 3 или 4 раза.

Если вы хотите встроить байт в RGB, вам потребуется 2 и 2/3 пикселя (3+3+2 компонента). Но для RGBA вам нужно всего два пикселя (4+4 компонента). Я покажу, как расширить ваш код, чтобы скрыть одно сообщение в RGBA, поскольку в данном случае это проще. Как указано выше, это увеличит вашу укрывистость в четыре раза. Есть довольно много изменений, которые происходят во всем коде, чтобы сделать это возможным, но их можно свести к следующему:

  • Ditch storageBit как то больше не нужен.
  • Вы можете встроить каждый байт в два пикселя. В первом пикселе вы встраиваете первые 4 бита в младшем бите компонентов A, B, G и R первого пикселя и последние 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;
   }

Встраивание различных секретов в каждый компонент цвета

Я изменил код, чтобы на этот раз вы могли выбрать, в каком цветовом компоненте вы хотите скрыть свой секрет из графического интерфейса. Это эффективно превосходит скрытую версию во всех RGBA. Здесь у вас есть универсальность, в которой цветовой компонент скрывает ваше сообщение, и, если у вас очень длинный, вы можете разделить его на четыре части. Для этого я внес следующие изменения в различные части кода:

  • Изменить значение storageBit внутренне на 0, 8, 16 или 24 в зависимости от того, выбрали ли вы A, R, G или B соответственно.
  • Этот выбор сделан в графическом интерфейсе, поэтому вам не нужно каждый раз перекомпилировать код для разных цветовых компонентов.

Чтобы применить изменения, начните чистить код, указанный на веб-сайте, и полностью замените следующие методы как для процессов кодирования, так и для декодирования.

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;
   }
Другие вопросы по тегам