摸鱼软件1:自动抓屏截图PPT软件

摸鱼软件1:自动抓屏截图PPT软件

前言

事情主要起源于数据库的网课,我那时候知道我们课后会有一个限时的测试,于是就产生了一个需求就是说自动截屏获得老师上课的PPT,上网搜了一圈,但是发现并没有现成的软件,于是我就在课后写了一个。(不要问我测试考的怎么样,那是一个悲伤的故事)

正文

我的软件主要使用了java编写,但是最后通过使用JSmooth打包成了大多数人可以使用.exe文件,方法和流程我后面会一一给出,
代码由于过多不会直接贴出,有兴趣的可以关注我的公众号:积淀智慧,回复摸鱼软件1即可获得,软件及源码,同时公众号里面写了软件的正确食用方法,欢迎大家的关注
代码整体没有设置界面,搭配快捷键十分好用,具体如下
在这里插入图片描述

1

最后实现的功能:最后实现的功能点有很多,我现在先讲最核心的部分自动截图抓屏软件,但实际上实现的功能点非常多,需要看其他功能点的描述的话,欢迎在评论区讨论回复
所有的功能如下所示:
​1.复制到粘贴板
2.控制截图屏幕
3.支持配置快捷键
4.支持双击功能
5.支持每隔一段时间自动截图
6.同时对图片去重,自动删去相同的图片
我们这篇会讲第5点和第6点,同时会讲下JSmooth配置上的问题

2

首先,我们首先要有指定区域的定时截图,这里我一开始犯了一个巨大的错误,因为前面花费了巨量的时间写了先截图然后再划定区域的代码,这是一般的截图所要做的事情,然而定时的截图需要做的事情是先划定区域,再定时截图,整体流程实际上是相反的,这是我们首先要记住的一个点,也是我第一版代码写完以后才发现的问题

3

那么第一个问题如何划定范围?
也就是说那个框框实际上是什么?
博主最后使用的java的Swing,所以那个框框实际上是JFrame,这是一件比较令人注意的事情,也是网上的资料非常稀少的地方,Swing中的JFrame是可以重写的

this.setUndecorated(true);

这个函数可以把窗口变成无修饰的样子,然后我们再把背景面板调整成透明,框框调整成红色就可以了

this.setContentPane(root);
		root.setLayout(new FlowLayout());	
		root.setBackground(new Color(0,0,0,0));
		root.setBorder(new LineBorder(new Color(255, 0, 0),10,true));

这样,我们就可以产生一个效果,如下图:
在这里插入图片描述
但是还有一个问题,重写窗口以后所有的事件都要重写,最核心的问题是:窗口无法移动,不能改变大小
所以下面的核心问题就是,窗口无法移动和不能改变大小的问题

窗口无法移动的问题

窗口移动是一个比较简单的事情,
首先我们思考一下窗口移动的流程:
1.当鼠标按下时候,记录下窗口此时的位置,同时设置一下标志变量,标志已经按下,
2.而后当鼠标拖动的时候,根据标志变量,我们获得鼠标当前的位置,把当前的位置赋值给窗口
3.当鼠标松开时候,标志变量重新设置回去
鼠标的监视器函数具体如下所示:

public void mouseReleased(MouseEvent e)
	{
		if (e.isMetaDown()) {
            showPopupMenu(e.getComponent(), e.getX(), e.getY());
        }
		pressed = false;
	}
	
	@Override
	public void mouseDragged(MouseEvent e)
	{	
		if(pressed) // pressed为true,表示当前鼠标左键被按下
		{
			// 根据鼠标位置,计算鼠标的位移
			Point pos = e.getLocationOnScreen();
			int dx = pos.x - startMousePos.x;
			int dy = pos.y - startMousePos.y;
				
			// 移动窗口位置
			Window w = getWindow();			
			
			// 改变大小,或者移动位置
			if(resizingX && resizingY)
				w.setSize( startWinSize.width + dx, startWinSize.height + dy);
			else if(resizingX)
				w.setSize( startWinSize.width + dx , startWinSize.height);
			else if(resizingY)
				w.setSize( startWinSize.width, startWinSize.height + dy);
			else
				w.setLocation(startWinPos.x + dx, startWinPos.y + dy);	
		}
	}

	@Override
	public void mouseMoved(MouseEvent e)
	{
		// 当鼠标到达右边缘、下边缘时,设置鼠标形状
		boolean isX = isNearRight(e.getX());
		boolean isY = isNearBottom(e.getY());
		
		if( isX && isY)
			comp.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR)); // 水平 & 竖直
		else if(isX)
			comp.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));  // 仅水平改变大小
		else if(isY)
			comp.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));  // 仅竖直改变大小
		else
			comp.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));		
	}

而窗口大小的改变同理:
1.当鼠标移动到边缘的时候(构造一个判断移动到边缘的函数),鼠标箭头改变一下
2.注意按下的时候,记录位置和大小
3.拖动的时候,改变大小和位置
4.松手的时候,标志变量改回去

4

窗口构造好了,然后是定时截图的问题
对了,这里插个小tips,窗口居中的办法:

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
		int x = ( screenSize.width - frame.getWidth())/2;
		int y = ( screenSize.height - frame.getHeight())/2;
		frame.setLocation(x,  y);	

1.java截图并保存的办法为:

 Robot robot  = new Robot();
	 
	            BufferedImage image = robot.createScreenCapture(rectangle);
	            ImageIO.write(image, imageFormat, new File(saveDir, k++ + "." + imageFormat));

Robot类中的方法,获得到上面窗口的rectangle后,将指定区域截图
2.而后是定时执行某个任务的方法

Task extends TimerTask
{public void run(){}
public void s{
 Timer t = new Timer();
	        //在指定时间安排指定任务
	        //第一个参数,是安排的任务,第二个参数是执行的时间,第三个参数是过多长时间再重复执行
	        Date date = new Date();
	        
	        t.schedule(new Task(), date,5000);}
	        }

5

上面的几个点组合到一起就基本实现指定区域定时截图了,然而还有一个问题,定时截图抓取ppt的时候,重复度过于高,大部分的图片PPT都是重复,所以,我又引入了一个相似度判断的函数:
我采用的是最简单的方法,但是效果非常好,计算rgb函数的灰度值,
最后根据各个分量得到相似度

public class ImagePerceptualHashSimilarity {

    public boolean perceptualHashSimilarity(BufferedImage src1, BufferedImage src2) {
        String code1 = this.perceptualHashSimilarity(src1);
        String code2 = this.perceptualHashSimilarity(src2);
        //System.out.println(code1);
        //System.out.println(code2);
        char[] ch1 = code1.toCharArray();
        char[] ch2 = code2.toCharArray();
        int diffCount = 0;
        for (int i = 0; i < 64; i++) {
            if (ch1[i] != ch2[i]) {
                diffCount++;
            }
        }
        //System.out.println(diffCount);
        return diffCount <=1;
    }

    public String perceptualHashSimilarity(BufferedImage src) {
        int width = 8;
        int height = 8;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics graphics = image.createGraphics();
        graphics.drawImage(src, 0, 0, 8, 8, null);
        int total = 0;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int pixel = image.getRGB(j, i);
                int gray = this.gray(pixel);
                total = total + gray;
            }
        }
        StringBuffer res = new StringBuffer();
        int grayAvg = total / (width * height);
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int pixel = image.getRGB(j, i);
                int gray = this.gray(pixel);
                if (gray >= grayAvg) {
                    res.append("1");
                } else {
                    res.append("0");
                }
            }
        }
        return res.toString();
    }

    private int gray(int rgb) {
        int a = rgb & 0xff000000;//将最高位(24-31)的信息(alpha通道)存储到a变量
        int r = (rgb >> 16) & 0xff;//取出次高位(16-23)红色分量的信息
        int g = (rgb >> 8) & 0xff;//取出中位(8-15)绿色分量的信息
        int b = rgb & 0xff;//取出低位(0-7)蓝色分量的信息
        rgb = (r * 77 + g * 151 + b * 28) >> 8;    // NTSC luma,算出灰度值
        return a | (rgb << 16) | (rgb << 8) | rgb;//将灰度值送入各个颜色分量
    }
}

6

计算出相似度之后,相似的图片会由后面的那一个替换掉前面的那一个,于是我又写了一个Judge()函数,这里Judge函数效率不高,主要是由于自动的定时截图其实和前面的截图有点不太兼容,所以采用的这种折中的办法

public  Judge(String Path) throws IOException {
    	//java找到一个路径下所有的.jpg文件
    	//文件按照创建时间再进行排序
    	File file = new File(Path);
    	File[] tempList = file.listFiles();
    	//这是排序
    	Arrays.sort(tempList, new Comparator<File>() {
            public int compare(File f1, File f2) {
                long diff = f1.lastModified() - f2.lastModified();
                if (diff > 0)
                    return 1;
                else if (diff == 0)
                    return 0;
                else
                    return -1;//如果 if 中修改为 返回-1 同时此处修改为返回 1  排序就会是递减
            }

            public boolean equals(Object obj) {
                return true;
            }

        });
//    	for(int i = 0 ;i < tempList.length;i++)
//    	{
//    		fileNameList.add(tempList[i].getAbsolutePath());
//    	}
    		//1,0个
    		if(tempList.length==1||tempList.length==0)
    			return;
    		//2个
    		else if(tempList.length==2)
    			{
    				//tempList[0]
    				//tempList[1]
    			//先得到地址,再得到码
    			BufferedImage image1 = ImageIO.read(tempList[0]);
    	        BufferedImage image2 = ImageIO.read(tempList[1]);
    	        ImagePerceptualHashSimilarity is = new ImagePerceptualHashSimilarity();
    	        boolean code = is.perceptualHashSimilarity(image1,image2);
    		if(code)
    		{
    			//删掉
    			
    			
    			//删除第一个,然后把第二改成第一的名字
    			tempList[1].renameTo(tempList[0]);
    			tempList[0].delete();
    			//这里是删除的File文件对象
    			return;
    		}
    		
    			}
    		//大于等于3个
    		//只判断最近的两个就可
    		else {
    			
    			for(int i=0;i<tempList.length-1;i++)
    			{
    				BufferedImage image1 = ImageIO.read(tempList[i]);
        	        BufferedImage image2 = ImageIO.read(tempList[i+1]);
        	        ImagePerceptualHashSimilarity is = new ImagePerceptualHashSimilarity();
        	        boolean code = is.perceptualHashSimilarity(image1,image2);
    				if(code)
    	    		{
    	    			//删掉
    					tempList[i+1].renameTo(tempList[i]);
    	    			tempList[i].delete();
    	    			//这里是删除的File文件对象
    	    		}
    			}
    			
    		}
    }
}

7.

其实就是这个简单的部分还是添加了一些小的点,比如截图会自动编号,我一开始想的是最简单的按照日期编号,后来改成了根据1,2,3…一个一个地按照顺序编号,当然,这里处理了一下第一次,第二次进入的问题,同时限制最大编号到了10000(应该不会比这个更多了吧…233333)

if(!FrameSupport.stop)
	        	{ Rectangle rectangle =frame.getBounds();
	 
	            Robot robot  = new Robot();
	 
	            BufferedImage image = robot.createScreenCapture(rectangle);
	            
	            int k=1;
	            for(int i=1;i<=10000;i++)
	            {
	            	File tFile =new File(saveDir, i + "." + imageFormat);
	            	if(!tFile.exists())
	            		{
	            			k=i;
	            			break;
	            		}
	            }
	            ImageIO.write(image, imageFormat, new File(saveDir, k++ + "." + imageFormat));
	            new Judge(saveDir);
	        	}

8

最后还有右键菜单的显示,可以控制开始,暂停和返回手动截图的功能

public void showPopupMenu(Component invoker, int x, int y) {
		JPopupMenu popupMenu = new JPopupMenu();
		JMenuItem startMenuItem = new JMenuItem("开始");
		JMenuItem stopMenuItem = new JMenuItem("暂停");
		JMenuItem returnMenuItem = new JMenuItem("返回");
		popupMenu.add(startMenuItem);
		popupMenu.add(stopMenuItem);
		popupMenu.add(returnMenuItem);
		
		startMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
                stop = false;
            }
		});
		
		stopMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
                stop=true;
            }
		});
		
		returnMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
                //注意这里的返回选项
				Swing2.frame.dispose();
				new JavaScreenCaptureTool();
            }
		});
		popupMenu.show(invoker, x, y);
	}

9.JSmooth配置形成.exe文件

为了让更多的使用,软件最后形成了.exe文件
首先下载JSmooth软件,注意需要JSmooth 0.9.9-7版本,
软件已经共享到公众号处,回复JSmooth可获得
然后是具体的操作手册,需要准备3样东西,软件图标,jar包,以及jre运行环境(在jdk文件夹中的jre文件夹就可),放到一个文件夹中
请如下操作:
1.选定windowed Wrapper
在这里插入图片描述
2.选择准备好图标,最下面打钩,在该文件夹下虚构一个.exe命名的最终文件
在这里插入图片描述
3.选定.jar包,同时选择主类,最后,jre文件夹下lib下的所有.jar文件都选在classpath下面
在这里插入图片描述
4.勾选齿轮运行

后记

获得软件和源码关注公众号:积淀智慧,回复摸鱼神器1
获得JSmooth,请后台回复JSmooth
想要这个软件其他的部分讲解的话,评论区回复,人多的话我会再写一篇关于手动截图功能的实现,功能点也蛮多

重磅预告:

我写好了摸鱼神器第二款,腾讯课堂全自动软件(自动签到,自动水群,自动回答问题),界面如下,现在测试中
在这里插入图片描述
想要的也欢迎关注公众号和本人博客
在这里插入图片描述

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值