我想学习 Java 中的隐写术,并在 github 上找到了一个存储库,它看起来很简单,可以从中学习:https://github.com/tigerlyb/Steganography-in-Java。我在文本嵌入和提取方面遇到问题 - 由于某种原因,某些字符被错误提取。我无法找出代码中的错误,因为它看起来是正确的,并且错误字符的位置似乎是随机的。
这是我之前提到的存储库中的代码:
// Steganography.java
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Steganography {
// embed secret information/TEXT into a "cover image"
public static BufferedImage embedText(BufferedImage image, String text) {
int bitMask = 0x00000001; // define the mask bit used to get the digit
int bit; // define a integer number to represent the ASCII number of a character
int x = 0; // define the starting pixel x
int y = 0; // define the starting pixel y
for(int i = 0; i < text.length(); i++) {
bit = (int) text.charAt(i); // get the ASCII number of a character
for(int j = 0; j < 8; j++) {
int flag = bit & bitMask; // get 1 digit from the character
if(flag == 1) {
if(x < image.getWidth()) {
image.setRGB(x, y, image.getRGB(x, y) | 0x00000001); // store the bit which is 1 into a pixel's last digit
x++;
}
else {
x = 0;
y++;
image.setRGB(x, y, image.getRGB(x, y) | 0x00000001); // store the bit which is 1 into a pixel's last digit
}
}
else {
if(x < image.getWidth()) {
image.setRGB(x, y, image.getRGB(x, y) & 0xFFFFFFFE); // store the bit which is 0 into a pixel's last digit
x++;
}
else {
x = 0;
y++;
image.setRGB(x, y, image.getRGB(x, y) & 0xFFFFFFFE); // store the bit which is 0 into a pixel's last digit
}
}
bit = bit >> 1; // get the next digit from the character
}
}
// save the image which contains the secret information to another image file
try {
File outputfile = new File("textEmbedded.png");
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
}
return image;
}
// extract secret information/Text from a "cover image"
public static void extractText(BufferedImage image, int length) {
System.out.print("Extracting: ");
int bitMask = 0x00000001; // define the mask bit used to get the digit
int x = 0; // define the starting pixel x
int y = 0; // define the starting pixel y
int flag;
char[] c = new char[length] ; // define a character array to store the secret information
for(int i = 0; i < length; i++) {
int bit = 0;
// 8 digits form a character
for(int j = 0; j < 8; j++) {
if(x < image.getWidth()) {
flag = image.getRGB(x, y) & bitMask; // get the last digit of the pixel
x++;
}
else {
x = 0;
y++;
flag = image.getRGB(x, y) & bitMask; // get the last digit of the pixel
}
// store the extracted digits into an integer as a ASCII number
if(flag == 1) {
bit = bit >> 1;
bit = bit | 0x80;
}
else {
bit = bit >> 1;
}
}
c[i] = (char) bit; // represent the ASCII number by characters
System.out.print(c[i]);
}
}
}
// Main.java
public class Main {
public static void main(String[] args) throws Exception {
try {
BufferedImage coverImageText = ImageIO.read(new File("originalPic.png"));
String s = "Java is a popular programming language, created in 1995.";
coverImageText = Steganography.embedText(coverImageText, s); // embed the secret information
Steganography.extractText(ImageIO.read(new File("textEmbedded.png")), s.length()); // extract the secret information
} catch(IOException e) {
System.out.print("Error: " + e);
}
}
}
问题是它确实正确提取了大部分字符,但少数字符除外。对于此示例,控制台中显示:
摘录:Java 是一种流行的编程语言,创建于 1995 年。
我尝试使用不同的输入文本,但总是有一些字符提取不正确。 textEmbedded.png 看起来像原始图像,但大小略有不同。有人可以帮我理解这里出了什么问题吗?
我对其进行了一些编辑,尽管我不确定为什么前一个不起作用......这个对我有用:
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Steganography {
// embed secret information/TEXT into a "cover image"
public static void embedText(BufferedImage image, String s, String fileName) throws Exception {
int n = s.length();
if (n * 8 > image.getWidth() * image.getHeight()) {
throw new Exception("The provided text is too large to be embedded in the image.");
}
int x = 0;
int y = 0;
for (int i = 0; i < n; i++) { // for every char in string
char c = s.charAt(i);
int binaryNum = (int) c; // get ASCII value
for (int j = 0; j < 8; j++) { // write every bit from binaryNum
int bit = binaryNum & 0x00000001; // take LSB
binaryNum = binaryNum >> 1; // move to next digit
int colorByte = image.getRGB(x, y);
if (bit == 1) {
image.setRGB(x, y, colorByte | 0x00000001);
} else {
image.setRGB(x, y, colorByte & 0xFFFFFFFE);
}
x++;
if (x >= image.getWidth()) {
x = 0;
y++;
}
}
}
System.out.println();
File outputfile = new File(fileName);
ImageIO.write(image, "png", outputfile);
}
// extract secret information/Text from a "cover image"
public static void extractText(BufferedImage image, int length) {
int x = 0, y = 0;
for (int i = 0; i< length; i++) {
int binaryNum = 0;
for (int j = 0; j<8; j++) {
int colorByte = image.getRGB(x, y);
int bit = colorByte & 0x00000001;
binaryNum = binaryNum >> 1;
if (bit == 1) {
binaryNum = binaryNum | 0x80;
}
x++;
if (x >= image.getWidth()) {
x = 0;
y++;
}
}
char c = (char) binaryNum;
System.out.print(c);
}
}
}