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

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

载体图像:
在这里插入图片描述

秘密信息:
在这里插入图片描述

伪装载体:
在这里插入图片描述

解密后载体图像:
在这里插入图片描述

解密取得的秘密信息:
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
没有积分的私聊我 看到消息百分百发给你 1、算法核心: 1、读取图片A,获得其RGB三个通道数据并转换成三个矩阵a1,a2,a3。 2、读取文件B,将其转换成比特流b。 3、遍历b,得到比特b1,b2,b3,b4,b5,b6等等,将b1代替a1第一个元素的最低,将b2代替a2第一个元素的最低,将b3代替a3第一个元素的最低,将b4代替a1第二个元素的最低,以此类推。 2、具体实现: 1、隐写: 1、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用java NIO读取被嵌入的文件,将其转换为byte数组,需要特别指出的是原生方法得到是byte类型的数组,但是算法实现需要更加精细的操作,所以还需要对得到的byte数组进行进一步的转换封装,将其转换成形如10101的数组。例如,读取文件得到byte数组的第一个元素为63,需将63转换为00111111数组。并且保存好文件的长度。 3、按照算法,遍历形如10101的数组 1、如果遍历到的值为0,将矩阵对应的矩阵元素与0xfe进行与运算,将最低置为0 2、如果遍历到的值为1,将矩阵对应的矩阵元素与0x01进行或运算,将最低置为1 4、将步骤3得到的经过经过隐写的矩阵写为一张新的图片。 3、读取 1、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用隐写步骤3得到的文件长度,遍历图片的像素矩阵,需要特别指出的是因为后续步骤还需要进行进一步的转化,所以这一步是将得到的“100100......”序列每八封装为一个数组,最终得到一些数组集合,每个数组包含八二进制序列。 3、将步骤2得到的数组进行转换,例如00111111应该转换为byte类型数值为63的数字,10111111转换为-63。这一步会得到一个byte类型的数组。 4、将步骤3得到的byte类型数组写入文件,需要指出的是写入的文件形式应该和隐写模块步骤二中读入的文件形式一致。 3、程序使用方法 1、安装Java8 2、使用命令行进入jar文件所在目录下,使用命令 java -jar 2016115130.jar 3、安装提示输入嵌入和被嵌入的文件名字,注意路径问题
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值