改变LSB的图像RGB值给予
我试图改变图像像素的LSB值,使得它与字符串“abc”匹配但添加1或0与奇值的像素被返回0 不一致值值这里是代码:改变LSB的图像RGB值给予
public static void main(String[] args) {
BufferedImage img = null;
try {
img = ImageIO.read(new File("a.jpg"));
} catch (IOException ex) {
}
int pixel[] = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
String s = "abc";
byte[] b = s.getBytes();
String f = "";
for (int i = 0; i < b.length; i++) {
f += Integer.toBinaryString(b[i]);
}
f.trim();
int[] newpixel = new int[pixel.length];
for (int i = 0; i < pixel.length; i++) {
if (i < f.length()) {
if (pixel[i] % 2 == 0) {
if (f.charAt(i) == '0') {
newpixel[i] = pixel[i];
}
if (f.charAt(i) == '1') {
newpixel[i] = pixel[i] + 1;
}
}
if (pixel[i] % 2 == 1) {
if (f.charAt(i) == '0') {
newpixel[i] = pixel[i] - 1;
}
if (f.charAt(i) == '1') {
newpixel[i] = pixel[i];
}
}
} else {
newpixel[i] = pixel[i];
}
}
o:
for (int i = 0; i < img.getWidth() * img.getHeight(); i++) {
if (i < f.length()) {
System.out.print(" " + f.charAt(i) + ":(" + pixel[i] + "," + newpixel[i] + ")");
} else {
break o;
}
}
}
并且输出是:
1:( - 11235948,-11235947)1:( - 11893363,0)0:( - 11893617,0) 0:( - 10577497,0)0:( - 11695976,-11695976)0:( - 12090996,-12090996)1:( - 11170168,-11170167)1:( - 10775924,-10775923)1:( - 972 0:( - 9658965,0)0:( - 9856341,0)0:( - 11236466,-11236466)1:( - 11564174,-11564173)0:( - 11431819,0)1: 10380136,-10380135)1:( - 10973290,-10973289)0:( - 12093056,-12093056)0:( - 10842985,0)0:( - 10118999,0)1:( - 11368034,-11368033)1: (-11630686,-11630685)
The modulo of a negative odd number does not return 1 in java,所以你的if (pixel[i] % 2 == 1)
块没有执行。从上面的链接中,您可以通过编写if ((((pixel[i] % 2) + 2) % 2) == 1)
来获得正数。然而,一个数字的奇偶性是排他性的,所以它不是偶数就是奇数。建议将代码更改为此代码
if (pixel[i] % 2 == 0) {
...
}
else {
...
}
虽然您的代码有另一个错误。行f += Integer.toBinaryString(b[i]);
将字符转换为二进制字符串,但如果ascii字符的值小于128,则转换将使用最小位数。例如,a = '1100001'
,它只有7位。你想填充0到左边来获得8位。快速搜索产生this和上面的行应更改为
f += String.format("%8s", Integer.toBinaryString(b[i])).replace(' ', '0');
如果我可以推荐给你的代码的一些可选的改进,如下
import java.util.Arrays;
public static void main(String[] args) {
BufferedImage img = null;
try {
img = ImageIO.read(new File("a.jpg"));
} catch (IOException ex) {
}
int pixel[] = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
int[] newpixel = Arrays.copyOf(pixel, pixel.length);
String s = "abc";
byte[] b = s.getBytes();
int count = 0;
for (int i = 0; i < b.length; i++) {
byte current_byte = b[i];
for (int j = 7; j >= 0; j--) {
int lsb = (current_byte >> j) & 1;
newpixel[count] = (pixel[count] & 0xfffffffe) + lsb;
System.out.println(lsb + ":(" + pixel[count] + "," + newpixel[count] + ")");
count++;
}
}
// Extraction sequence
String secret = "";
int bit = 0;
for (int i = 0; i < b.length; i++) {
int ascii = 0;
for (int j = 7; j >=0; j--) {
ascii += (newpixel[bit] & 1) << j;
bit++;
}
secret += (char)ascii;
}
System.out.print(secret);
}
注意我会做到这一点:
Arrays.copyOf()
是保持原始图像的副本比较差异的缘故。通常,我只是直接编辑0。
你不需要字节转换为1和0的字符串,因为你需要这些数字为整数以后。以下循环使用right bitshift和bitwise and操作将比特从最高有效位(最左边)逐个提取到最低位。
for (int j = 7; j >=0; j--) {
int lsb = (b[i] >> j) & 1;
}
而不是检查一个像素的LSB的值,你可以将它清零,然后从上面的循环添加LSB。您可以使用按位和操作来实现此目的。一个像素由四个字节组成,每个像素的最大值为255(0xff)。这些字节对应于alpha透明度,红色,绿色和蓝色通道(称为ARGB)。你可以阅读关于它here。
newpixel[count] = (pixel[count] & 0xfffffffe) + lsb;
提取过程与嵌入相反。但这里有一个窍门。该程序在提取整个消息之前不知道要读取多少个像素。你想要做的是引入一个长度变量,它等于8 * b.length
。您可以分配前16个像素,以像您的角色一样在1秒和0秒内隐藏此数字。提取然后读取这第一个16像素,计算有多少像素要读取,并从第17个像素开始。
:但我认为你的代码会使代码的提取有点困难。你可以建议我如何提取字符串。 – 2014-10-29 16:20:11
我已经用提取snipet更新了答案。 – Reti43 2014-10-29 17:37:49
:在将newpixel写入jpg文件时,应该是什么颜色模型?我尝试了几乎所有类型的颜色模型,但提取并不成功,虽然我的代码在使用像素数组时工作正常。 – 2014-11-06 15:32:12