【发布时间】:2015-06-30 23:29:24
【问题描述】:
我有这段代码,尝试使用最低有效位方法对图像中的消息进行编码。我想不通的是,当没有消息要编码时,如何结束消息的编码。
它一直持续到循环结束。
我尝试过像限制这样的计数器。与我在解码部分所做的相同,但无济于事,这就是我将其删除的原因。
我包含这些方法是因为它们已被使用并可用于包含计数器,以识别消息是否已完成编码并可以停止迭代
编码和解码在构造函数中。
public class Steganography {
public static SteganographyGUI gui;
public static String binarizedMessage = "", encodedMessage = "", decodedMessage = "";
public static int count = 0, limit = 0;
public static BufferedImage image;
public static int width, height, numLSB;
public Steganography() {
if(gui.isEncode()){
try {
String messageToBeHidden = gui.getMessage();
binarizedMessage = stringToBinary(messageToBeHidden);
File input = new File(gui.getPath());
image = ImageIO.read(input);
width = image.getWidth();
height = image.getHeight();
gui.appendStatus("File Name: " + gui.getFileName() + "\nWidth: " + width + "\nHeight: " + height + "\nLSB: " + gui.getSelectedLSB());
numLSB = gui.getSelectedLSB();
//encoding
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
Color c = new Color(image.getRGB(j, i));
int red = binaryToInteger(insertMessage(integerToBinary((int)(c.getRed())),numLSB));
int green = binaryToInteger(insertMessage(integerToBinary((int)(c.getGreen())),numLSB));
int blue = binaryToInteger(insertMessage(integerToBinary((int)(c.getBlue())),numLSB));
Color newColor = new Color(red,green,blue);
image.setRGB(j,i,newColor.getRGB());
}
}
gui.appendStatus("Binarized message is: " + binarizedMessage);
File output = new File(gui.getOutput()+"lossy.jpg");
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(1f);
FileImageOutputStream outputStream = new FileImageOutputStream(output); //For example, FileImageOutputStream
jpgWriter.setOutput(outputStream);
IIOImage outputImage = new IIOImage(image, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
File output2 = new File(gui.getOutput()+"lossless.jpg");
ImageIO.write(image, "png", output2);
gui.appendStatus("Message \""+ messageToBeHidden +"\" was encoded in "+ gui.getFileName() +".\nOutput files are: " + gui.getOutput() + "lossy.jpg \n\t"+ gui.getOutput() + "lossless.jpg");
} catch (Exception e) {}
}
else{
File input = new File(gui.getPath());
String encodedData = "";
try {
image = ImageIO.read(input);
} catch (IOException ex) {}
width = image.getWidth();
height = image.getHeight();
gui.appendStatus("File Name: " + gui.getFileName() + "\nWidth: " + width + "\nHeight: " + height + "\nLSB: " + gui.getSelectedLSB());
numLSB = gui.getSelectedLSB();
String eData = "";
//decoding
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
Color c = new Color(image.getRGB(j, i));
encodedData += getLSB(integerToBinary((int)(c.getRed())),numLSB);
encodedData += getLSB(integerToBinary((int)(c.getGreen())),numLSB);
encodedData += getLSB(integerToBinary((int)(c.getBlue())),numLSB);
if(limit >= 8 * numLSB){
break;
}
}
}
int counter = 0;
while(counter * 8 < encodedData.length()){
int index = counter * 8;
String str = encodedData.substring(index, index + 8);
eData += str;
if(!str.equals("00000000")){
encodedMessage += new Character((char)Integer.parseInt(str, 2)).toString();
counter++;
}
else{
eData = eData.substring(0,eData.length()-8);
break;
}
}
gui.appendStatus("Data decoded was: \"" + eData + "\".");
gui.appendStatus("Message decoded was: \"" + encodedMessage + "\".");
gui.appendStatus("Number of characters: " + counter);
}
reinitialize();
}
public static void reinitialize(){
binarizedMessage = encodedMessage = decodedMessage = "";
count = limit = width = height = numLSB = 0;
}
public static String stringToBinary(String s){
byte[] bytes = s.getBytes(); // http://stackoverflow.com/questions/917163/convert-a-string-like-testing123-to-binary-in-java
StringBuilder binary = new StringBuilder();
for (byte b : bytes) {
int val = b;
for (int i = 0; i < 8; i++){
binary.append((val & 128) == 0 ? 0 : 1);
val <<= 1;
}
}
return binary.toString();
}
public static String integerToBinary(int i){
return String.format("%8s", Integer.toBinaryString(i)).replace(' ', '0'); //http://stackoverflow.com/questions/21856626/java-integer-to-binary-string
}
public static int binaryToInteger(String s){
return Integer.parseInt(s, 2); //http://stackoverflow.com/questions/7437987/how-to-convert-binary-string-value-to-decimal
} //http://stackoverflow.com/questions/10178980/how-to-convert-a-binary-string-to-a-base-10-integer-in-java
public static String clearLSB(String s, int x){
StringBuilder result = new StringBuilder(s); //http://stackoverflow.com/questions/6952363/java-replace-a-character-at-a-specific-index-in-a-string
for (int i = 8 - x; i < 8; i++){
result.setCharAt(i, '0');
}
return result.toString(); //http://www.tutorialspoint.com/java/lang/stringbuilder_tostring.htm
}
public static String insertMessage(String s, int x){
String result = clearLSB(s, x);
StringBuilder temp = new StringBuilder(result);
for (int i = 8 - x; i < 8; i++){
if(count < binarizedMessage.length())
temp.setCharAt(i, binarizedMessage.charAt(count++));
}
return temp.toString();
}
public static String getLSB(String s, int x){
String result = "";
for (int i = 8 - x; i < 8; i++){
result += s.charAt(i);
if(s.charAt(i) == '0')
limit += 1;
else
limit = 0;
}
return result;
}
public static String binaryToText(String s){
StringBuilder sb = new StringBuilder();
count = 0;
while(count<s.length()){
StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < 8; i++){
if(count<s.length())
sb2.append(s.charAt(count++));
else
sb2.append('0');
break;
}
//binary to char and append to sb
sb.append((char)Integer.parseInt( sb.toString(), 2 ) );
}
return sb.toString();
}
public static void main(String[] args) {
gui = new SteganographyGUI();
gui.setVisible(true);
}
}
编辑:
似乎第一个问题已解决,但又产生了另一个问题。
现在我已经根据 Reti43 下面的答案更改了我的解码和编码,我无法让我的 dataComparison 工作。我尝试应用您指出的解码线,但我无法获得图片中的编码数据。
这是原始数据比较
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import javax.imageio.ImageIO;
public class DataComparison {
public static DataComparisonGUI gui;
public static BufferedImage image, image2;
public static int width, height, lsb, limit = 0;
public static String lossyData = "", losslessData = "", lsData = "", lyData = "";
public static String lossyMessage = "", losslessMessage = "";
public static int[][][] cLossyData, cLosslessData;
public DataComparison(){
lsb = gui.getLSB();
try{
File lossy = new File(gui.getLossyPath());
File lossless = new File(gui.getLosslessPath());
image = ImageIO.read(lossy);
image2 = ImageIO.read(lossless);
width = image.getWidth();
height = image.getHeight();
cLossyData = new int[height][width][3];
cLosslessData = new int[height][width][3];
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
Color c = new Color(image.getRGB(j, i));
Color c2 = new Color(image2.getRGB(j, i));
lossyData += getLSB(integerToBinary((int)(c.getRed())),lsb);
lossyData += getLSB(integerToBinary((int)(c.getGreen())),lsb);
lossyData += getLSB(integerToBinary((int)(c.getBlue())),lsb);
losslessData += getLSB(integerToBinary((int)(c2.getRed())),lsb);
losslessData += getLSB(integerToBinary((int)(c2.getGreen())),lsb);
losslessData += getLSB(integerToBinary((int)(c2.getBlue())),lsb);
cLossyData[i][j][0] = c.getRed();
cLossyData[i][j][1] = c.getGreen();
cLossyData[i][j][2] = c.getBlue();
cLosslessData[i][j][0] = c2.getRed();
cLosslessData[i][j][1] = c2.getGreen();
cLosslessData[i][j][2] = c2.getBlue();
if(limit >= 8 * lsb){
break;
}
}
}
int counter = 0;
while(counter * 8 < losslessData.length()){
int index = counter * 8;
String str = lossyData.substring(index, index + 8);
String str2 = losslessData.substring(index, index + 8);
lyData += str;
lsData += str2;
if(!str2.equals("00000000")){
lossyMessage += new Character((char)Integer.parseInt(str, 2)).toString();
losslessMessage += new Character((char)Integer.parseInt(str2, 2)).toString();
counter++;
}
else{
lyData = lyData.substring(0,lyData.length()-8);
lsData = lsData.substring(0,lsData.length()-8);
break;
}
}
int i = 0, lostBits = 0;
while(i < lyData.length()){
if(lyData.charAt(i) != lsData.charAt(i)){
lostBits++;
}
i++;
}
gui.appendStatus("Data decoded was (Lossless):\n\"" + lsData + "\".");
gui.appendStatus("Data decoded was (Lossy):\n\"" + lyData + "\".");
gui.appendStatus("Number of lsb: " + lsb);
gui.appendStatus("Number of bits (hidden message): " + counter * 8);
gui.appendStatus("Number of lost bits (hidden message): " + lostBits);
float z = ((lostBits*100)/(counter*8));
String percentage = String.format("%.04f", z);
gui.appendStatus("Percentage of lost bits (hidden message): " + percentage + "%");
gui.appendStatus("Message decoded was (Lossless): \"" + losslessMessage + "\".");
gui.appendStatus("Message decoded was (Lossy): \"" + lossyMessage + "\".");
gui.appendStatus("Number of characters: " + counter);
int counterR = 0, counterG = 0, counterB = 0;
for(int p = 0; p < height; p++){
for(int q = 0; q < width; q++){
if(cLosslessData[p][q][0] != cLossyData[p][q][0]){
counterR++;
}
else if(cLosslessData[p][q][1] != cLossyData[p][q][1]){
counterG++;
}
else if(cLosslessData[p][q][2] != cLossyData[p][q][2]){
counterB++;
}
}
}
gui.appendStatus("Total RGB values: " + width * height * 3);
gui.appendStatus("Altered Red values: " + counterR);
gui.appendStatus("Altered Green values: " + counterG);
gui.appendStatus("Altered Blue values: " + counterB);
gui.appendStatus("Total Altered values: " + (counterR + counterG + counterB));
z = ((counterR + counterG + counterB)*10000)/(width * height * 3);
percentage = String.format("%.02f", z/100);
gui.appendStatus("Percentage Altered values: " + percentage + "%");
reinitialize();
} catch (Exception e) {}
}
public static void reinitialize(){
losslessData = lossyData = lsData = lyData = losslessMessage = lossyMessage = "";
limit = width = height = lsb = 0;
Arrays.fill(cLossyData, 0);
Arrays.fill(cLosslessData, 0);
}
public static String integerToBinary(int i){
return String.format("%8s", Integer.toBinaryString(i)).replace(' ', '0'); //http://stackoverflow.com/questions/21856626/java-integer-to-binary-string
}
public static String getLSB(String s, int x){
String result = "";
for (int i = 8 - x; i < 8; i++){
result += s.charAt(i);
if(s.charAt(i) == '0')
limit += 1;
else
limit = 0;
}
return result;
}
public static void main(String[] args) {
// TODO code application logic here
gui = new DataComparisonGUI();
gui.setVisible(true);
}
}
上面的代码是基于我原来的编码/解码算法工作的。不停止循环的那个。我尝试编辑代码并应用新的解码算法,但我无法让它工作。
【问题讨论】:
-
numLSB究竟包含什么?你能告诉我们binaryToInteger、insertMessage和integerToBinary的方法吗?就目前而言,numLSB位于循环之外并且不会更新,因此仅包含消息的所有 1 和 0 才有意义。但我看不到你增加一个计数器来嵌入下一个二进制位的地方。 -
@Reti43
numLSB包含一个 int 值,用于确定每个 rgb 值中要更改的位数。方法binaryToInteger、insertMessage和insertMessage位于下方。我在 insertmessage 方法中增加了一个计数器。从 0 开始的 count++。 -
您不应该编辑问题来彻底改变主题。而是创建一个新问题。这个问题涉及退出一些循环,而不是它对问题中未提及的其他一些代码的影响,直到问题循环中断问题得到解决。