欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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();
        }
    }
}

载体图像:
4.Java实现LSB(最低有效位)算法--隐藏文字

秘密信息:
4.Java实现LSB(最低有效位)算法--隐藏文字

伪装载体:
4.Java实现LSB(最低有效位)算法--隐藏文字

解密后载体图像:
4.Java实现LSB(最低有效位)算法--隐藏文字

解密取得的秘密信息:
4.Java实现LSB(最低有效位)算法--隐藏文字