摸鱼软件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
想要这个软件其他的部分讲解的话,评论区回复,人多的话我会再写一篇关于手动截图功能的实现,功能点也蛮多
重磅预告:
我写好了摸鱼神器第二款,腾讯课堂全自动软件(自动签到,自动水群,自动回答问题),界面如下,现在测试中
想要的也欢迎关注公众号和本人博客