Сохранение сообщения в 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;
}