随机生成验证码
直接上代码,如果需要用上的按需修改代码即可。
public class ImgVerification {
// 存储验证码的文本字符串
private String imgText = null;
/**
* 本方法会根据指定的宽度,高度,背景颜色,验证码位数,干扰线位数来绘制一张图片并且保存到图像返回
*
* @param imgWidth - 指定的宽度
* @param imgHeight - 指定的高度
* @param bgColor - 指定的背景颜色
* @param verificationNumber - 指定的验证码位数
* @param disturbNumber - 指定的干扰线位数
*
* @return - 返回内容为图片验证码的图像
*/
public ImageIcon getImgVerification(int imgWidth, int imgHeight, Color bgColor, int verificationNumber, int disturbNumber) {
// 创建图片缓冲区
BufferedImage image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
// 得到绘制环境
Graphics2D g = (Graphics2D) image.getGraphics();
// 设置图片背景
g.setColor(bgColor);
// 绘制图片轮廓
g.fillRect(0, 0, imgWidth, imgHeight);
// 存储验证码的文本字符串
StringBuffer imgText = new StringBuffer();
// 可选字符
String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 可选字体
String[] fontNames = { "宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312" };
// 生成指定的字符并且绘制
for (int i = 0; i < verificationNumber; i++) {
// 生成的一个随机字符
String ch = codes.charAt(new Random().nextInt(codes.length())) + "";
imgText.append(ch);
// 设置当前字符的X轴坐标
float chX = i * imgWidth / verificationNumber;
// 设置当前字符的Y轴坐标
float chY = imgHeight - new Random().nextInt(10);
// 设置当前字符的字体,样式,大小
String fontName = fontNames[new Random().nextInt(fontNames.length)];
int style = new Random().nextInt(4);
int size = imgHeight - new Random().nextInt(30);
g.setFont(new Font(fontName, style, size));
// 设置当前字符的颜色
int red = new Random().nextInt(256);
int green = new Random().nextInt(256);
int blue = new Random().nextInt(256);
g.setColor(new Color(red, green, blue));
// 绘制这个字符
g.drawString(ch, chX, chY);
}
// 开始绘制干扰线
for (int i = 0; i < disturbNumber; i++) {
// 生成干扰线的坐标
int X1 = new Random().nextInt(imgWidth);
int Y1 = new Random().nextInt(imgHeight);
int X2 = new Random().nextInt(imgWidth);
int Y2 = new Random().nextInt(imgHeight);
// 设置干扰线的粗细
g.setStroke(new BasicStroke(new Random().nextFloat() + new Random().nextInt(5) + 1));
// 设置干扰线的颜色
int red = new Random().nextInt(256);
int green = new Random().nextInt(256);
int blue = new Random().nextInt(256);
g.setColor(new Color(red, green, blue));
// 绘制干扰线
g.drawLine(X1, Y1, X2, Y2);
}
// 将验证码的文本字符串传出方法体中
this.imgText = imgText.toString();
// 返回图片验证码的输入流形式
ImageIcon img = new ImageIcon(image);
return img;
}
// 返回验证码的文本字符串
public String getImgText() {
return imgText;
}
}
在Swing界面上显示图片
// 用标签类来显示验证码
ImgVerification Picture = new ImgVerification();
ImageIcon img = Picture.getImgVerification(200, 50, new Color(255, 255, 255), 4, 3);
JLabel label = new JLabel(img);
public void mouseClicked(MouseEvent e) {
// 更换验证码方式
img = Picture.getImgVerification(200, 50, new Color(255, 255, 255), 4, 3);
label.setIcon(img);
}
效果图如下所示:
图像识别
因为是要实现在屏幕上寻找一部分,比如我的屏幕上有QQ,微信等软件的快捷方式,这功能就是要找到QQ的快捷方式,返回它在屏幕上的坐标信息,然后我们就能将鼠标移动到QQ,点击它。第一步就是截取屏幕上的QQ图片,我创建一个文件夹专门放置这类照片信息,以后就在这图片库提取图片信息,然后与屏幕信息进行对比,看看屏幕是否有这图片信息,这就是最低等级的图像识别。
首先,我们就需要把图片库里面的图片加载到内存中
/**
* 本方法根据文件夹名从当前项目中找文件夹并且返回文件夹所有照片文件
*
* @param FolderName - 指定的文件夹名字
*
* @return - 返回指定文件夹内的所有照片文件
*/
public static List<BufferedImage> readFiles(String FolderName) {
try {
// 获取当前目录下的指定文件夹
File Folder = new File(
System.getProperty("user.dir") + File.separator + FolderName);
// 遍历文件夹的所有文件
if (Folder.isDirectory()) {
java.util.List<BufferedImage> files = new ArrayList<>();
String[] filelist = Folder.list();
// 将所有照片存储并且返回
for (int i = 0; i < filelist.length; i++) {
File file = new File(Folder + File.separator + filelist[i]);
// 判断是否为照片文件
String[] strArray = file.getName().split("\\.");
int suffixIndex = strArray.length - 1;
// 存储照片文件
if (!file.isDirectory()
&& (strArray[suffixIndex].equals("png") || strArray[suffixIndex].equals("jpg"))) {
BufferedImage img = ImageIO.read(file);
files.add(img);
}
}
return files;
}
} catch (Exception e) {
e.getStackTrace();
}
return null;
}
将图片库的所有文件加载进内存后,就把图片信息转化为数字信息。
/**
* 本方法将图片集合转化为图片数据集合
*
* @param imgs - 指定图片集合
*
* @return - 指定图片数据集合
*/
private List<int[][]> getImagesGRB(List<BufferedImage> imgs) {
List<int[][]> ImagesData = new ArrayList<>();
for (int i = 0; i < imgs.size(); i++) {
int width = imgs.get(i).getWidth();
int height = imgs.get(i).getHeight();
int[][] img = new int[width][height];
for (int w = 0; w < width; w++)
for (int h = 0; h < height; h++) {
img[w][h] = imgs.get(i).getRGB(w, h);
}
ImagesData.add(img);
}
return ImagesData;
}
图片已经好了,下面就是获取屏幕相关信息了
// 获取屏幕尺寸
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int windows_width = gd.getDisplayMode().getWidth();
int windows_height = gd.getDisplayMode().getHeight();
// 截屏
BufferedImage winImage = robot.createScreenCapture(new Rectangle(0, 0, windows_width, windows_height));
屏幕图像已经获取,直接图像识别走起!
/**
* 本方法会根据图片数据从屏幕里找寻相同的图片信息,找到后会返回其对应的坐标集合
*
* @param Window - 屏幕图像
* @param ImagesData - 指定图片数据集合
*
* @return - 返回图片在屏幕的坐标集合
*/
public static List<PictureIdentifyWork> FindAllImgData(BufferedImage Window, List<int[][]> ImagesData) {
List<PictureIdentifyWork> mouseMessages = new ArrayList<>();
// 解析屏幕图片数据
int width = Window.getWidth();
int height = Window.getHeight();
int[][] WindowData = new int[width][height];
for (int w = 0; w < width; w++)
for (int h = 0; h < height; h++) {
WindowData[w][h] = Window.getRGB(w, h);
}
// 将屏幕与全部目标图片对比
for (int i = 0; i < ImagesData.size(); i++) {
// 获取图片尺寸
int imgWidth = ImagesData.get(i).length;
int imgHeight = ImagesData.get(i)[0].length;
a: {
for (int x = 0; x < width - imgWidth; x++) {
for (int y = 0; y < height - imgHeight; y++) {
// 判断图片的四个顶点的RGB是否相等
if (equalsRGB(ImagesData.get(i)[0][0], WindowData[x][y])
&& equalsRGB(ImagesData.get(i)[imgWidth - 1][0], WindowData[x + imgWidth - 1][y])
&& equalsRGB(ImagesData.get(i)[imgWidth - 1][imgHeight - 1], WindowData[x + imgWidth - 1][y + imgHeight - 1])
&& equalsRGB(ImagesData.get(i)[0][imgHeight - 1], WindowData[x][y + imgHeight - 1])) {
// 如果相等,进行二次匹配确认
int biggerX = 0;
int biggerY = 0;
boolean flag = true;
b: {
for (int smallerX = 0; smallerX < imgWidth; smallerX++) {
biggerX = x + smallerX;
for (int smallerY = 0; smallerY < imgHeight; smallerY++) {
biggerY = y + smallerY;
// 如果对应点数据不同为假
if (!equalsRGB(ImagesData.get(i)[smallerX][smallerY], WindowData[biggerX][biggerY])) {
flag = false;
break b;
}
}
}
}
if (flag) {
System.out.println("在屏幕上找到图片了");
System.out.println("坐标:( " + x + " , " + y + " )");
// 这是专门存储数据的类
PictureIdentifyWork mouseXY = new PictureIdentifyWork();
x += (int) (Math.random() * imgWidth);
y += (int) (Math.random() * imgHeight);
mouseXY.setX(x);
mouseXY.setY(y);
mouseMessages.add(mouseXY);
break a;
}
}
}
}
}
}
// 返回所有图片对应窗口坐标
return mouseMessages;
}
// 对比方法
public static boolean equalsRGB(int RGB1, int RGB2) {
int R1 = (RGB1 & 0xff0000) >> 16;
int G1 = (RGB1 & 0xff00) >> 8;
int B1 = (RGB1 & 0xff);
int R2 = (RGB2 & 0xff0000) >> 16;
int G2 = (RGB2 & 0xff00) >> 8;
int B2 = (RGB2 & 0xff);
if (Math.abs(R1 - R2) < 5 && Math.abs(G1 - G2) < 5 && Math.abs(B1 - B2) < 5) {
return true;
} else {
return false;
}
}
最后是老生常谈的模拟鼠标操作
for(int i = 0; i < findAllImgData.size(); i++) {
Robot robot = new Robot();
// 修复JDK8的移动不正确的BUG(亲测在JDK11,该BUG已经修复)
for (int j = 0; j < 6; j++) {
robot.mouseMove(findAllImgData.get(i).getX(), findAllImgData.get(i).getY());
}
robot.delay(500);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.delay(500);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
最简单的图像识别功能已经实现了,缺点就是不能识别动态图片,也无法识别缩放比例后的屏幕图像。如果要实现这些功能就得优化改进一下算法了。下面说一下其他小功能。
扫描二维码关注公众号,回复:
11627093 查看本文章
自动关机
其实这功能也没有什么难的,网上一大把,直接上代码了。
// 立刻关机,后面的00就是0秒后关机的意思了,你自己可以设置关机时间
Runtime.getRuntime().exec("shutdown -s -t 00");
// 取消关机
Runtime.getRuntime().exec("shutdown -a");
当然还有其他的关机方式,直接百度就能查到,就不全部举例了。
最后结语
脚本1.0的功能已经全部说完了,以后或许会出后续卷,主要是讲解我的脚本2.0,它与脚本1.0的不同点在于它可以实现后台操作窗口,而不像脚本1.0只能坐在电脑面前看着脚本的运行(鼠标被程序征用了),同时脚本2.0也优化了算法,可以更快的定位图像的坐标,但是我平时也只是使用脚本1.0来挂机,采用的也是最初的取点对比方式,因为图像识别的计算量大,本人爱惜自家电脑,避免电脑过度劳累,从我做起!