import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author ArtemisKhryso
* @time 2021/4/28
*/
public class LSB {
//图片宽高
private static int imgHight = 1;
private static int imgWidth = 1;
private static int imgHight2= 1;
private static int imgWidth2 = 1;
//像素矩阵集合
private static ArrayList<String[][]> resList = new ArrayList<>();
//原像素矩阵
public static void main(String[] args) throws IOException {
//加密
encryption("img/zui10/载体图像.png","img/zui10/秘密图像预处理6.png");
//解密
Decrypt("img/zui10/已伪装图像.png");
}
/**
* 初始化并加密
* @param src 载体图像路径
* @param src2 秘密图像路径
* @throws IOException
*/
public static void encryption(String src, String src2) throws IOException {
System.out.println("载体图像路径:"+src+" 秘密图像路径:"+src2);
System.out.println("开始加密....");
//图像操纵对象
BufferedImage imgSrc = ImageIO.read(new File(src));
BufferedImage imgSrc2 = ImageIO.read(new File(src2));
//图片类型
int imgType = 5;
imgHight = imgSrc.getHeight();
imgWidth = imgSrc.getWidth();
imgHight2 = imgSrc2.getHeight();
imgWidth2 = imgSrc2.getWidth();
//创建存储像素信息的三个矩阵
resList.clear();
resList.add(ru(imgWidth,imgHight));
resList.add(ru(imgWidth2,imgHight2));
resList.add(ru(imgWidth,imgHight));
//记录载体图像像素信息到第一个矩阵里
for (int i = 0; i < imgWidth; i++) {
for (int j = 0; j < imgHight; j++) {
resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
}
}
//记录秘密图像像素信息到第二个矩阵里
for (int i = 0; i < imgWidth2; i++) {
for (int j = 0; j < imgHight2; j++) {
resList.get(1)[i][j] = Integer.toBinaryString(imgSrc2.getRGB(i, j));
}
}
//默认从左上角开始隐藏
for (int i = 0; i < imgWidth; i++) {
//如果小于隐藏图像的宽度,列号
if (i<imgWidth2){
for (int j = 0; j < imgHight; j++) {
//且小于隐藏图像的高度,行号
//则为秘密图像的宽高范围,应发生置换
if (j<imgHight2){
char[] chars1 = resList.get(0)[i][j].toCharArray();
char[] chars3 = chars1;
char[] chars2 = resList.get(1)[i][j].toCharArray();
//就将对应的位置信息放置在对应像素的透明度、红、绿、蓝通道的低4bit位
//采用U型替换规则,加密顺时针替换,解密逆时针替换
//蓝通道
chars3[31] = chars2[24];
chars3[30] = chars2[25];
chars3[29] = chars2[26];
chars3[28] = chars2[27];
//绿通道
chars3[23] = chars2[16];
chars3[22] = chars2[17];
chars3[21] = chars2[18];
chars3[20] = chars2[19];
//红通道
chars3[15] = chars2[8];
chars3[14] = chars2[9];
chars3[13] = chars2[10];
chars3[12] = chars2[11];
//透明度通道
chars3[7] = chars2[0];
chars3[6] = chars2[1];
chars3[5] = chars2[2];
chars3[4] = chars2[3];
//保存置换后的像素信息至第三个矩阵中
resList.get(2)[i][j] = String.valueOf(chars3);
}else {
//保存没有置换的像素信息至第三个矩阵中
resList.get(2)[i][j] = String.valueOf(resList.get(0)[i][j].toCharArray());
}
}
}else {
for (int j = 0; j < imgHight; j++) {
resList.get(2)[i][j] = String.valueOf(resList.get(0)[i][j].toCharArray());
}
}
}
//输出加密结果
oimg(resList.get(2),"已伪装图像",imgWidth,imgHight);
System.out.println("加密完成....");
}
public static void Decrypt(String src) throws IOException {
//图像操纵对象
BufferedImage imgSrc = ImageIO.read(new File(src));
//图片类型
int imgType = 5;
imgWidth = imgSrc.getWidth();
imgHight = imgSrc.getHeight();
System.out.println(imgWidth2);
System.out.println(imgHight2);
resList.clear();
resList.add(ru(imgWidth,imgHight));
resList.add(ru(imgWidth2,imgHight2));
for (int i = 0; i < imgWidth; i++) {
if (i<imgWidth2){
for (int j = 0; j < imgHight; j++) {
if (j<imgHight2){
char[] chars1 = Integer.toBinaryString(imgSrc.getRGB(i, j)).toCharArray();
char[] chars2 = new char[32];
char[] chars3 = new char[32];
for (int h = 0; h < 32; h++){
chars2[h] = '0';
chars3[h] = '0';
}
chars2[24] = chars1[24];
chars2[25] = chars1[25];
chars2[26] = chars1[26];
chars2[27] = chars1[27];
chars3[24] = chars1[31];
chars3[25] = chars1[30];
chars3[26] = chars1[29];
chars3[27] = chars1[28];
chars2[16] = chars1[16];
chars2[17] = chars1[17];
chars2[18] = chars1[18];
chars2[19] = chars1[19];
chars3[16] = chars1[23];
chars3[17] = chars1[22];
chars3[18] = chars1[21];
chars3[19] = chars1[20];
chars2[8] = chars1[8];
chars2[9] = chars1[9];
chars2[10] = chars1[10];
chars2[11] = chars1[11];
chars3[8] = chars1[15];
chars3[9] = chars1[14];
chars3[10] = chars1[13];
chars3[11] = chars1[12];
chars2[0] = chars1[0];
chars2[1] = chars1[1];
chars2[2] = chars1[2];
chars2[3] = chars1[3];
chars3[0] = chars1[7];
chars3[1] = chars1[6];
chars3[2] = chars1[5];
chars3[3] = chars1[4];
resList.get(0)[i][j] = String.valueOf(chars2);
resList.get(1)[i][j] = String.valueOf(chars3);
}else {
resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
}
}
}else {
for (int j = 0; j < imgHight; j++) {
resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
}
}
}
oimg(resList.get(0),"解密后载体图像",imgWidth,imgHight);
oimg(resList.get(1),"解密后秘密图像",imgWidth2,imgHight2);
System.out.println("解密完成....");
}
/**
* 生产像素矩阵
* @param width
* @param hight
* @return
*/
public static String[][] ru(int width,int hight){
return new String[width][hight];
}
/**
* 图片输出方法
* @param matrix
* @param name
* @param imgWidth
* @param imgHight
*/
public static void oimg(String[][] matrix, String name,int imgWidth, int imgHight){
BufferedImage imgRes = new BufferedImage(imgWidth, imgHight, 5);
for (int i = 0; i < imgWidth; i++) {
for (int j = 0; j < imgHight; j++) {
// System.out.println("第"+name+"个 i:"+i+" j:"+j+" 值:"+Integer.parseUnsignedInt(r[i][j],2));
imgRes.setRGB(i,j,Integer.parseUnsignedInt(matrix[i][j],2));
}
}
File imgOut = new File("img/zui10/"+name+".png");
//输出文件
try {
ImageIO.write(imgRes, "png", imgOut);
} catch (IOException e) {
e.printStackTrace();
}
}
}
通道是什么?
一个像素占一个int(32bit)
从左往右00000000 00000000 00000000 00000000
第一个八位是决定像素蓝光的
第二个绿
第三个红
第四个透明度
每个八位对其颜色的影响也是从左往右降低 越低位影响越大 越能保持像素的原始信息 所以把低八位隐藏在高八位里