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

Java_最不重要位替换(LSB)基于24位BMP图片

程序员文章站 2024-01-24 17:12:34
...

向BMP图片中隐藏一段文字并保存,从保存的图片中提取文字.

Java代码:


import java.awt.BorderLayout;  
import java.awt.Color;  
import java.awt.Dimension;
import java.awt.Graphics;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
import java.io.BufferedInputStream;  
import java.io.BufferedOutputStream;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;
import java.util.Enumeration;

import javax.swing.JFileChooser;  
import javax.swing.JFrame;
import javax.swing.JMenu;  
import javax.swing.JMenuBar;  
import javax.swing.JMenuItem;  
import javax.swing.JPanel;  
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.FontUIResource;  
  
/**
 * 
 * @ClassName: 信息隐藏_LSB技术_于BMP位图 
 * @Description: 基于24位BMP图片,运用LSB技术对文本信息进行隐藏
 * @author: 
 * @date: 2018年4月23日 下午8:11:52
 */

public class 信息隐藏_LSB技术_于BMP位图  extends JFrame{ 
	
	private static final long serialVersionUID = 1L;
	int map[][];//保存像素颜色的数组  
    MyPanel center;//绘图面板  
    File selectFile;//读取的文件  
    int width;//图像宽度  
    int height;//图像高度  
    byte temp1[];//读取BMP文件的前18个字节信息  
    byte temp2[];//读取BMP文件的后28个字节信息  
    JScrollPane scrollpane;//滚动面板
    JTextArea infoJt;//信息文本区
    JMenuItem open;
    JMenuItem save;
    JMenuItem hide;
    JMenuItem show;
    int disWidth=1000;
    int disHeight=700;
    public 信息隐藏_LSB技术_于BMP位图() {  
    	setUIFont(new FontUIResource("微软雅黑", 0, 20));
        this.setLayout(new BorderLayout());//最好先设置布局再添加组件  
        //初始化画图面板  
        center=new MyPanel();  
        center.setBackground(Color.WHITE);  
        center.setBackground(Color.GRAY);
      //  center.setPreferredSize(new Dimension(200, 300));
        scrollpane=new JScrollPane(center);//用center初始化滚动面板  
      //  scrollpane.setPreferredSize(new Dimension(200,100)); 
        infoJt=new JTextArea();
        infoJt.setLineWrap(true);
        infoJt.setWrapStyleWord(true);
       JScrollPane infoJs=new JScrollPane(infoJt);
        infoJs.setPreferredSize(new Dimension(disWidth, 300));
        MyListener lis=new MyListener();  
          
        //初始化菜单栏  
        JMenuBar menuBar=new JMenuBar();  
        JMenu fileMenu=new JMenu("file");  
         open=new JMenuItem("open");  
         save=new JMenuItem("save");
        JMenu LSBMenu=new JMenu("LSB");  
         hide=new JMenuItem("hide");  
         show=new JMenuItem("show");
        open.addActionListener(lis);  
        save.addActionListener(lis);
        hide.addActionListener(lis);
        show.addActionListener(lis);
        fileMenu.add(open);  
        fileMenu.add(save);  
        menuBar.add(fileMenu);
        LSBMenu.add(hide);
        LSBMenu.add(show);
        menuBar.add(LSBMenu);
        this.setJMenuBar(menuBar);  
        this.add(scrollpane,BorderLayout.CENTER);//加入的是滚动面板
        this.add(infoJs,BorderLayout.SOUTH);
        this.setTitle("LSB隐藏器");  
        this.setSize(disWidth, disHeight); 
        this.setLocationRelativeTo(null);//设置窗体出现在屏幕中间
        this.setDefaultCloseOperation(3);  
        this.setVisible(true);
       
    }  
    /** 
     * 读取bmp文件 
     */  
    public void readBMP()  
    {  
        try {  
            FileInputStream fis=new FileInputStream(selectFile);  
            BufferedInputStream bis=new BufferedInputStream(fis);  
            byte[] wb=new byte[4];//读取宽度的字节数组  
            byte[] hb=new byte[4];//读取高度的字节数组  
            temp1=new byte[18];  
            bis.read(temp1);//bis.skip(18);//跳过前18个byte  
            bis.read(wb);//读取宽度  
            bis.read(hb);//读取高度  
            
            width=byteToint(wb);  
            height=byteToint(hb);  
            map=new int[height][width];
            int skip=4-width*3%4;//得到每行要跳过的数字(与windows 系统机制有关)  
            temp2=new byte[28];  
            bis.read(temp2);//bis.skip(28); 
            if(temp1[10]==55)//偏移量为55,此位图已经隐入了信息数据
            	bis.read();//跳过1字节
            for(int i=height-1;i>0;i--)  
            {  
                for(int j=0;j<width;j++)  
                {  
                    int blue=bis.read();  
                    int green=bis.read();  
                    int red=bis.read();
                    Color c=new Color(red,green,blue);  
                    map[i][j]=c.getRGB();  
                }  
                if(skip!=4)  
                bis.skip(skip);  
            }  
            bis.close();  
            center.setPreferredSize(new Dimension(width,height));  
            javax.swing.SwingUtilities.updateComponentTreeUI(center);//这里必须要用updateComponentTreeUI(center)函数  
        //不能用repaint()函数  
          
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
      
    public void writeBMP()  
    {  
        try {  
            FileOutputStream fos=new FileOutputStream(selectFile);  
            BufferedOutputStream bos=new BufferedOutputStream(fos);  
            bos.write(temp1);//  
            bos.write(intTobyte(width,4));//写入宽度  
            bos.write(intTobyte(height,4));//写入高度  
            bos.write(temp2);
            int skip=0;  
            if(width*3/4!=0)  
            {  
                skip=4-width*3%4;  
            }
            if(temp1[10]==55)
            	bos.write(new byte[1]);
            for(int i=height-1;i>=0;i--)  
            {  
                for(int j=0;j<width;j++)  
                {  
                    Color c=new Color(map[i][j]);  
                    int blue=c.getBlue();  
                    int green=c.getGreen();  
                    int red=c.getRed();  
                    bos.write(blue);  
                    bos.write(green);  
                    bos.write(red);  
                }  
                if(skip!=0)  
                    bos.write(new byte[skip]);  
            }  
            bos.flush();  
            fos.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
    //字节转int  
    public static  int byteToint(byte b[])  
    {  
        int t1=(b[3]&0xff)<<24;  
        int t2=(b[2]&0xff)<<16;  
        int t3=(b[1]&0xff)<<8;  
        int t4=b[0]&0xff;  
        //System.out.println(b[1]&0xff);//输出的是一个整形数据  
        //在java中,设计int和比int位数来的小的类型b,如byte,char等,都是先把小类型扩展成int再来运算,  
        //return( t1<<24)+(t2<<16)+(t3<<8)+t4;//必须加括号  
        return t1+t2+t3+t4;  
    }  
    //int 转byte  
    public static byte[] intTobyte(int a,int len)  
    {  
        byte []t=new byte[len];  
            t[0]=(byte) ((a&0xff));  
            if(len>1)  
            t[1]=(byte)((a&0xff00)>>8);  
            if(len>2)  
            t[2]=(byte)((a&0xff0000)>>16);  
            if(len>3)  
            t[3]=(byte)((a&0xff000000)>>24);  
        return t;  
    }  
    
    private static void setUIFont(javax.swing.plaf.FontUIResource f) {
		Enumeration<Object> keys = UIManager.getDefaults().keys();
		while (keys.hasMoreElements()) {
			Object key = keys.nextElement();
			Object value = UIManager.get(key);
			if (value instanceof javax.swing.plaf.FontUIResource) {
				UIManager.put(key, f);
			}
		}
	}
    
  
    /**
     * LSB处理
     * @author 
     * @date 2018年4月22日
     */
    class LSB{
    	public  boolean hide() {
    			temp1[10]+=1;//将位图数据偏移量增1,作为是否隐入数据的标识,此时temp1[10]=55;
    			String info=infoJt.getText();
    			char[] infoChs=info.toCharArray();
    			int index=0,endIndex=0;
    			String str;
    			byte[] infoBins=new byte[infoChs.length*16];
    			char[] wordBins=new char[16];
    			for(int i=0;i<infoChs.length;i++) {
    				str=intToWordBinaryString((int)infoChs[i]);
    				str=new StringBuilder(str).reverse().toString();
    				wordBins=str.toCharArray();
    				for(int j=0;j<16;j++) {
    					infoBins[index++]=(byte)(wordBins[j]-'0');
    				}
    			}
    			index=0;
    			for(int i=height-1;i>0;i--)  
                {  
                    for(int j=0;j<width;j++)  
                    { 
                    	if(index<infoBins.length) {
                    		map[i][j]=map[i][j]&0xfffffffe;
                    		if(infoBins[index]==1) {
                    			map[i][j]+=1;
                    		}
                    		index++;
                    	}
                    	else 
                    	{
                    		map[i][j]=map[i][j]&0xfffffffe;//结束标记,一个字的最低位为0
                    		endIndex++;
                    		if(endIndex>=16)
                    		return true;
                    	}
                    }
                }
    			return false;
    	}
    	
    	public String show() {
    		String info="";
    		byte[] wordBins=new byte[16];
    		int index=0;
    		String wordStr="";
    		int wordInt;
    		outer:for(int i=height-1;i>=0;i--) {
    			for(int j=0;j<width;j++) {
    				wordBins[index++]=(byte)(map[i][j]&0x00000001);
    				if(index>=16) {
    					for(int k=15;k>=0;k--) {
    						wordStr+=wordBins[k];
    					}
    					wordInt=Integer.parseInt(wordStr,2);
    					if(wordInt!=0) {
    						info+=(char)wordInt;
    					}else {
    						break outer;
    					}
    					index=0;wordStr="";
    				}
    			}
    		}
    		return info;
    	}
    	
    	private String intToWordBinaryString(int i) {
			StringBuilder sb = new StringBuilder(Integer.toBinaryString(i));
			while (sb.length() < 16) {
				sb.insert(0, "0");
			}
			return sb.toString();
		}
    }
    /** 
     * 绘图面板 
     * 
     * 
     */  
    class MyPanel extends JPanel{  
		private static final long serialVersionUID = 1L;

		public void paint(Graphics g) {  
            super.paint(g);  
            if(map!=null)  
            {  
                for(int i=0;i<map.length;i++)  
                {  
                    for(int j=0;j<map[i].length;j++)  
                    {  
                        g.setColor(new Color(map[i][j]));  
                        g.drawLine(j+200, i, j+200, i);
                    }
                }  
            }  
        }  
    }  
      
    class MyListener implements ActionListener{  
        JFileChooser fileChosser;  
        MyListener()  
        {  
            FileNameExtensionFilter filter=new FileNameExtensionFilter("24位位图(*.bmp)", "bmp");  
            fileChosser=new JFileChooser();  
            fileChosser.setFileFilter(filter);  
            fileChosser.setCurrentDirectory(new File("\\"));  
        }  
        public void actionPerformed(ActionEvent e) { 
        	JMenuItem jmi = (JMenuItem) e.getSource();
            if(jmi==open)//选择的是打开  
            {  
                int choose=fileChosser.showOpenDialog(null);  
                if(choose==JFileChooser.APPROVE_OPTION)//点击的是确定按钮  
                {  
                    selectFile=fileChosser.getSelectedFile();  
                    readBMP();
                    infoJt.setText("图片打开成功!\n");
                    if(temp1[10]==54) {
                    infoJt.append("最多可嵌入"+height*width/8+"个字节的信息!\n");
                    }else if(temp1[10]==55) {
                    	infoJt.append("此图片已经隐入有信息!");
                    }
                } 
            }  
            else if(jmi==save)//选择的是保存
            {  
                int choose=fileChosser.showSaveDialog(null);  
                if(choose==JFileChooser.APPROVE_OPTION)  
                {  
                    selectFile=fileChosser.getSelectedFile();  
                    writeBMP();  
                    infoJt.setText("保存成功!"); 
                }  
            }
            else if(jmi==hide) {
            	if(new LSB().hide()) {
            		infoJt.setText("信息隐入成功!");
            	}else{
            		infoJt.setText("信息隐入出现不确定问题!");
            	}
            	
            }
            else if(jmi==show) {
            	String info=new LSB().show();
            	infoJt.setText("隐入的信息内容:\n");
            	infoJt.append(info);
            }
        }  
          
    }  
      
      
    public static void main(String[] args) {  
       new 信息隐藏_LSB技术_于BMP位图();
    }  
}   

效果图:

Java_最不重要位替换(LSB)基于24位BMP图片

Java_最不重要位替换(LSB)基于24位BMP图片

程序操作步骤:

file-->open,LSB-->hide,file-->save,file-->open,LSB-->show.

相关标签: BMP LSB JAVA