如何更改它以将消息存储到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;
}