4.Java实现LSB(最低有效位)算法--隐藏文字
程序员文章站
2024-03-19 14:31:58
...
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author ArtemisKhryso
* @time 2021/5/16
*/
public class LSB2 {
//图片宽高
private static int imgHight = 1;
private static int imgWidth = 1;
//像素矩阵集合
private static ArrayList<String[][]> resList = new ArrayList<>();
public static void main(String[] args) throws IOException {
//加密
encryption("img/zui11/qq.png", "F:\\secretin.txt");
//解密
Decrypt("img/zui11/已伪装图像.png", "F:\\secretout.txt");
}
/**
* 加密秘密信息
* @param carrier 伪装载体路径
* @param secret 秘密信息路径
* @throws IOException
*/
public static void encryption(String carrier,String secret) throws IOException {
System.out.println("开始加密....");
/**
* 载体图像预处理
*/
File carrierImg = new File(carrier);
//图像操纵对象
BufferedImage imgSrc = ImageIO.read(carrierImg);
//图片类型
int imgType = 5;
imgHight = imgSrc.getHeight();
imgWidth = imgSrc.getWidth();
//创建存储像素信息的2个矩阵
resList.clear();
resList.add(ru(imgWidth,imgHight));
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));
}
}
/**
* 秘密信息预处理
*/
File secretInfo = new File(secret);
FileInputStream fis = new FileInputStream(secretInfo);
// 秘密信息长度
int length = (int) secretInfo.length();
// 秘密信息字节数组
int[] infoByteArray = new int[length];
// 将秘密信息按字节读取存储在infoByteArray中
for (int i = 0; i<length; i++){
infoByteArray[i] = fis.read();
}
int time = 0;
//默认从左上角开始隐藏
for (int i = 0; i < imgWidth; i++) {
for (int j = 0; j < imgHight; j++) {
//如果秘密信息已存储完毕
if (time >=length) {
resList.get(1)[i][j] = resList.get(0)[i][j];
}else {
// 像素二进制
char[] pixelChars = resList.get(0)[i][j].toCharArray();
// 文件字节二进制
char[] fileBin = Integer.toBinaryString(infoByteArray[time]).toCharArray();
// 中文
if(fileBin.length == 8){
//蓝通道
pixelChars[31] = fileBin[7];
pixelChars[30] = fileBin[6];
pixelChars[29] = fileBin[5];
//绿通道
pixelChars[23] = fileBin[4];
pixelChars[22] = fileBin[3];
pixelChars[21] = fileBin[2];
//红通道
pixelChars[15] = fileBin[1];
pixelChars[14] = fileBin[0];
}else {
// 英文
pixelChars[31] = fileBin[5];
pixelChars[30] = fileBin[4];
pixelChars[29] = fileBin[3];
//绿通道
pixelChars[23] = fileBin[2];
pixelChars[22] = fileBin[1];
pixelChars[21] = fileBin[0];
//红通道
pixelChars[15] = '0';
pixelChars[14] = '0';
}
//保存置换后的像素信息至第二个矩阵中
resList.get(1)[i][j] = String.valueOf(pixelChars);
time++;
}
}
}
// 关闭资源
fis.close();
/**
* 储存秘密信息字节长度
*/
// 最后一个像素数组
char[] endPixel = new char[32];
// 文件长度的二进制表示
char[] lengthBin = Integer.toBinaryString(length).toCharArray();
//赋初值
for (int y = 0; y<32; y++){
if (y<8){
endPixel[y] = '1';
}else {
endPixel[y] = '0';
}
}
int t = 0;
// 从后往前数秘密信息长度个位置开始放置信息长度二进制信息
for (int h = 32 - lengthBin.length; h <32; h++) {
endPixel[h] = lengthBin[t];
t++;
}
// 将秘密信息的长度隐藏在最后一个像素里
resList.get(1)[imgWidth-1][imgHight-1] = String.valueOf(endPixel);
System.out.println("加密信息:" + secretInfo.getName() + " 位置:" + secretInfo.getAbsolutePath());
System.out.println("伪装载体:" + carrierImg.getName() + " 位置:" + carrierImg.getAbsolutePath());
// 输出伪装好的图像
oimg(resList.get(1),"已伪装图像",imgWidth,imgHight);
System.out.println("加密完成....");
}
public static void Decrypt(String camouflage, String secretOut) throws IOException {
// 解密开始
System.out.println("解密开始....");
File camouflageImg = new File(camouflage);
//图像操纵对象
BufferedImage imgSrc = ImageIO.read(camouflageImg);
//取出秘密信息长度
char[] endPixel = Integer.toBinaryString(imgSrc.getRGB(imgWidth - 1, imgHight - 1)).toCharArray();
char[] lengthBin = new char[24];
int t = 31;
for (int h = 23; h >=0; h--) {
lengthBin[h] = endPixel[t];
t--;
}
// 秘密信息长度
int length = Integer.parseUnsignedInt(String.valueOf(lengthBin),2);
//图片类型
int imgType = 5;
imgWidth = imgSrc.getWidth();
imgHight = imgSrc.getHeight();
resList.clear();
resList.add(ru(imgWidth,imgHight));
File out = new File(secretOut);
FileOutputStream fos = new FileOutputStream(out);
int timwe = 0;
for (int i = 0; i < imgWidth; i++) {
for (int j = 0; j < imgHight; j++) {
if (timwe>=length){
resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
}else {
char[] pixelChars = Integer.toBinaryString(imgSrc.getRGB(i, j)).toCharArray();
char[] fileBin = new char[8];
//蓝通道
fileBin[7] = pixelChars[31];
fileBin[6] = pixelChars[30];
fileBin[5] = pixelChars[29];
//绿通道
fileBin[4] = pixelChars[23];
fileBin[3] = pixelChars[22];
fileBin[2] = pixelChars[21];
//红通道
fileBin[1] = pixelChars[15];
fileBin[0] = pixelChars[14];
// 将像素信息写入矩阵
resList.get(0)[i][j] = String.valueOf(pixelChars);
// 按字节写出
fos.write(Integer.parseUnsignedInt(String.valueOf(fileBin), 2));
timwe++;
}
}
}
fos.close();
oimg(resList.get(0),"解密后载体图像",imgWidth,imgHight);
System.out.println(out.getName()+ " 输出位置:" + out.getPath() );
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++) {
imgRes.setRGB(i,j,Integer.parseUnsignedInt(matrix[i][j],2));
}
}
File imgOut = new File("img/zui11/"+name+".png");
//输出文件
try {
ImageIO.write(imgRes, "png", imgOut);
System.out.println(name+ ".png 输出位置:" + imgOut.getAbsolutePath() );
} catch (IOException e) {
e.printStackTrace();
}
}
}
载体图像:
秘密信息:
伪装载体:
解密后载体图像:
解密取得的秘密信息: