Java版跳一跳

java

浏览数:100

2019-1-13


Jump_Jump

    public static void main(String[] args) throws Exception {
        // 删除临时文件
        File f = new File(filePath);
        if (!f.exists()) {
            f.mkdir();
        } else {
            for (File ff : f.listFiles()) {
                ff.delete();
            }
        }

        // 记录日志
        PrintStream print = new PrintStream(new FileOutputStream(new File(filePath + "log.txt"), false), true, "UTF-8");
        System.setOut(print);

        JTextArea textArea = initJFrame();
        int i = 0;
        while (true) {
            if (!jump) {
                Thread.sleep(5000);
                continue;
            }
            i++;
            // 100次清空文本域一次
            if (i % 100 == 0) {
                textArea.setText("");
            }
            String fileName = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date()) + "_" + i + ".png";
            File file = new File(filePath + fileName);
            System.out.println(fileName + "--------------------------------获取图片");
            textArea.append(fileName.substring(11, fileName.length() - 4) + "---------------获取图片\r\n");
            textArea.setCaretPosition(textArea.getDocument().getLength());

            // 更新图片 保留五位数不足补0 在文件夹排序用
            pullImg(file);
            // 加载图片
            BufferedImage image = getImage(file);
            if (image == null) {
                throw new RuntimeException("图片不能为空!!!");
            }
            // 重新设置全局宽高
            new Jump_Jump(image.getWidth(), image.getHeight());
            // 获取起始点
            int[] startPoint = findStartPoint(image);
            // 判断小人起始点不为空,并且不是重新开始按键(有的人头像是小人一样的颜色) -16726153为开始按钮上的绿色
            if (startPoint != null && image.getRGB(GAMEOVER_X2, GAMEOVER_Y2) != -16726153) {
                // 获取背景色上下值
                int[] backGround = getBackGround(image);
                // 获取顶点坐标
                int[] topPoint = getTopPoint(image, startPoint, backGround);
                // 获取白点为目标点
                // int[] endPoint = getWhitePoint(image, topPoint);
                // 如果不是白点则继续找最大最小值
                // if (endPoint == null) {
                // 获取XY最大最小值坐标
                int[] maxMinXY = getMaxMinXY(image, startPoint, topPoint);
                // 获取目标坐标
                int[] endPoint = findEndPoint(image, maxMinXY);
                // } else {
                // System.out.println("'\t\t\t------------找到白点!!!");
                // }
                // 小人到目标坐标距离 勾股定理
                double distance = (Math.sqrt(Math.pow((endPoint[0] - startPoint[0]), 2) + Math.pow((endPoint[1] - startPoint[1]), 2)));
                // 计算按压时间
                double pm = PM + ((DISTANCE_CRITICAL - distance) / 8000);

                System.out.println("顶点 [" + endPoint[2] + "," + endPoint[3] + "]\t左点 [" + endPoint[4] + "," + endPoint[5] + "]\t右点 ["
                        + endPoint[6] + "," + endPoint[7] + "]");
                System.out.println("起点 [" + startPoint[0] + "," + startPoint[1] + "]" + "\t终点 [" + endPoint[0] + "," + endPoint[1] + "]");
                System.out.println("距离: " + (int) distance + "\t系数: " + String.format("%.3f", pm));

                if (jump) {
                    textArea.append("距离: " + (int) distance + "\t系数: " + String.format("%.3f", pm) + "\r\n");
                    textArea.setCaretPosition(textArea.getDocument().getLength() - 1);
                    // 按压开始跳 最小300毫秒
                    press(Math.max((int) (distance * pm), 0));
                }
                // 写出图片加入跳的信息
                drawImage(image, file, startPoint, endPoint, (int) distance + "*" + String.format("%.3f", pm) + "="
                        + (int) (distance * pm));
                // 获取图片前睡几秒等小人落地,连续命中白点,放出去的圈圈影响顶点寻找
                Thread.sleep(200 + Math.max((int) distance, 600));
            } else {
                // 找不到小人起始点,就是重新开始
                textArea.append("无法获小人取起始点!!!\r\n");
                textArea.setCaretPosition(textArea.getDocument().getLength());

                // 判断开始按钮
                if (image.getRGB(GAMEOVER_X2, GAMEOVER_Y2) == -16726153) {
                    // 重新按压
                    execute(String.format("adb shell input tap %d %d", GAMEOVER_X + new Random().nextInt(100),
                            GAMEOVER_Y + new Random().nextInt(50)));
                }

                // 歇一会,等到小人落地
                Thread.sleep(5000);
                // execute("adb shell input keyevent 4");
                // execute("adb shell input keyevent 4");
                // execute("adb shell input keyevent 26");
                continue;
            }
        }
    }

    /**初始化窗口*/
    public static JTextArea initJFrame() {
        JFrame f = new JFrame("跳一跳");// 实例化一个窗体框架
        Container c = f.getContentPane();// 获取窗口容器
        c.setLayout(new FlowLayout());// 设置布局模式
        JPanel p1 = new JPanel(new GridLayout(1, 2, 10, 0));// 开始暂停按钮面板
        JPanel p2 = new JPanel(new GridLayout(1, 1, 0, 0));// 文本域面板
        JPanel p3 = new JPanel(new GridLayout(2, 1, 0, 2));// 距离系数面板
        JButton b1 = new JButton("调整系数");// 调整系数按钮
        final JButton b2 = new JButton("开 始");// 开始暂停按钮
        final JTextField t1 = new JTextField(10);// 文本框
        final JTextArea t2 = new JTextArea("点击开始......\r\n");// 文本域

        // 设置文本框
        t1.setText(PM + "");// 初始化文本框
        t1.setFont(new Font("微软雅黑", Font.PLAIN, 20));// 设置字体
        t1.setBackground(new Color(222, 222, 222));// 设置背景色
        t1.setCaretPosition(t1.getText().length());// 设置光标位置
        t1.setForeground(Color.BLUE);// 设置文本颜色
        t1.setCaretColor(Color.RED);// 设置光标颜色
        t1.setSelectionColor(Color.CYAN);// 设置文本选中颜色

        // 设置文本域
        t2.setLineWrap(true);// 超出范围自动换行显示
        t2.setWrapStyleWord(true);
        t2.setEditable(false);// 设置不可编辑
        t2.setTabSize(4);// 设置Tab长度
        t2.setFont(new Font("微软雅黑", Font.PLAIN, 14));// 设置字体
        t2.setBackground(Color.LIGHT_GRAY);// 设置背景颜色
        t2.setForeground(Color.RED);// 设置字体颜色
        t2.setMargin(new Insets(5, 5, 15, 5));// 设置边距

        // 设置按钮
        b2.setFocusable(false);// 按钮文字外面的框框
        b2.setFont(new Font("微软雅黑", Font.BOLD, 34));// 设置按钮字体
        b1.setFocusable(false);
        b1.setFont(new Font("微软雅黑", Font.BOLD, 14));

        // 点击事件
        ActionListener action = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String command = e.getActionCommand();
                // 开始功能
                if ("开 始".equals(command) || "Enter".equals(command)) {
                    b2.setText("暂 停");
                    jump = true;
                    t2.append("开 始......\r\n");
                    // 暂停功能
                } else if ("暂 停".equals(command) || "Esc".equals(command)) {
                    b2.setText("开 始");
                    jump = false;
                    t2.append("暂 停......\r\n");
                    // 调整系数功能
                } else if ("调整系数".equals(command)) {
                    String text = t1.getText();
                    // 判断文本框输入参数的类型
                    boolean matches = Pattern.compile("^[-\\+]?[.\\d]*$").matcher(text).matches();
                    if (matches) {
                        PM = Double.parseDouble(text);
                        t2.append("距离系数调整为: " + PM + "\r\n");
                    } else {
                        t2.append(text + " 不是数字,请输入数字!!!\r\n");
                    }
                }
                t2.setCaretPosition(t2.getDocument().getLength());
            }
        };

        // 开始暂停按钮点击事件
        b2.addActionListener(action);
        b2.setMnemonic(KeyEvent.VK_ENTER);
        b2.registerKeyboardAction(action, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        b1.registerKeyboardAction(action, "Esc", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        // 距离系数按钮点击事件
        b1.addActionListener(action);

        // 设置面板
        p1.setPreferredSize(new Dimension(290, 100));// 面板大小
        p2.setPreferredSize(new Dimension(290, 160));
        p1.setBorder(BorderFactory.createTitledBorder("功能"));// 包裹面板的框框
        p2.setBorder(BorderFactory.createTitledBorder("输出"));
        p3.setBorder(BorderFactory.createTitledBorder("距离系数"));
        p1.add(p3);// 添加调整距离系数面板
        p1.add(b2);// 添加开始暂停按钮
        p2.add(new JScrollPane(t2));// 添加文本域且文本域滚动
        p3.add(t1);// 添加距离系数文本框
        p3.add(b1);// 添加距离系数按钮

        // 设置窗口
        c.add(p1);// 添加功能面板
        c.add(p2);// 添加输出面板
        f.setFocusable(true);// 设置获取焦点
        f.setSize(300, 300); // 设置大小
        f.setLocation(1000, 20); // 设置窗体位置
        f.setVisible(true); // 设置是否可见
        f.setResizable(false);// 不能改变窗体大小
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setAlwaysOnTop(true);// 设置窗口是否总在最上面
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);// 当点击按钮时退出程序
            }
        });
        f.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
            }
        });

        return t2;
    }

    /**修正距离转时间参数*/
    public static double getPM(double distance) {
        // 正常情况下, 远的跳的远 近的跳的近
        double pm = 0d;
        if (pm == 1000) {
        } else if (distance >= 660) {
            return 1.52d - distance / 10000;
        } else if (distance >= 600 && distance < 660) {
            return 1.53d - distance / 10000;
        } else if (distance >= 550 && distance < 600) {
            return 1.54d - distance / 10000;
        } else if (distance >= 500 && distance < 550) {
            pm = 9;// 跳近了 改小 [1-100]
        } else if (distance >= 450 && distance < 500) {
            pm = 11;
        } else if (distance >= 300 && distance < 450) {
            pm = 13;
        } else if (distance >= 250 && distance < 300) {
            pm = 15;
        } else if (distance >= 200 && distance < 250) {
            pm = 13;
        } else if (distance >= 150 && distance < 200) {
            pm = 11;
        } else if (distance < 150) {
            pm = 9;
        }
        return ((560d - distance) / (pm * 100)) + 1.42;
    }

    /** 找小人 开始点  判断小人颜色*/
    public static int[] findStartPoint(BufferedImage image) {
        int maxX = -1;
        int minX = W;
        int maxY = -1;
        int minY = H;
        for (int x = 0; x < W; x++) {
            // 小人坐标都是在高度1/4距离到高度4/3距离内
            for (int y = H / 4; y < H * 3 / 4; y++) {
                // 判断小人当前坐标是否在小人颜色误差范围 小人颜色为 54 60 100 误差范围10
                if (isRange(image, x, y, 54, 60, 100, 10)) {
                    maxX = Math.max(maxX, x);
                    minX = Math.min(minX, x);
                    maxY = Math.max(maxY, y);
                    minY = Math.min(minY, y);
                }
            }
        }
        // 取小人颜色一样最大最小X坐标求平均值,实测要减去3像素 小人底座最下方到方块中心 实测要减去18像素
        int[] res = { (maxX + minX) / 2 - 3, maxY - 18 };
        if (res[0] <= 0 || res[1] <= 0) {
            return null;
        }
        return res;
    }

    /** 获取屏幕背景色 Y轴渐变色,取上下值*/
    public static int[] getBackGround(BufferedImage image) {
        // 背景色取最下方 左 中 右 避免遮挡
        // 背景色左方
        int leftRgb = image.getRGB(0, H - 1);
        // 背景色右方
        int rightRgb = image.getRGB(W - 1, H - 1);
        // 背景色左方4/1
        int leftRgb2 = image.getRGB((int) (W / 4), H - 1);
        // 背景色右方4/1
        int rightRgb2 = image.getRGB((int) (W * 3 / 4), H - 1);
        // 背景色中间
        int centerRgb = image.getRGB((int) (W / 2), H - 1);
        // 默认取左边
        int rgb = leftRgb;
        // 左右不相等,判定取左还是右
        if (leftRgb != rightRgb) {
            // 如果右边和右边四分之一相等,并且左边和左边四分之一不相等,或者右边等于一半时的值,则取右边
            if ((leftRgb != leftRgb2 && rightRgb == rightRgb2) || rightRgb == centerRgb) {
                rgb = rightRgb;
            }
        }
        // 背景色最上方,下方颜色
        int[] topRGB = getMyRGB(image, 0, BACKGROUND_MIN_X);
        Color downRGB = new Color(rgb);
        return new int[] { topRGB[0], topRGB[1], topRGB[2], downRGB.getRed(), downRGB.getGreen(), downRGB.getBlue() };
    }

    /**获取顶点 */
    public static int[] getTopPoint(BufferedImage image, int[] startPoint, int[] backBroundRGB) {
        // 找顶点,记录顶点颜色 从图片1/4位置开始,到小人Y轴结束
        for (int y = H / 4; y < startPoint[1]; y++) {
            for (int x = 100; x < W - 100; x++) {
                boolean isBody = false;
                // 过滤小人,防止小人比目标高 小人高度208(底座18),宽度75
                if (Math.abs(startPoint[0] - x) < BODY_X / 2 + 5 && Math.abs(startPoint[1] - y) < BODY_Y - 18 + 5) {
                    isBody = true;
                }
                // 如果不在背景色范围,则是顶点,找到顶点则停止
                if (!isBackBround(image, x, y, backBroundRGB, 5) && !isBody) {
                    // 顶点向下找30个点如果有背景色,则跳出继续找顶点,抗干扰音符颜色一样最大Y30
                    boolean b = true;
                    for (int i = 0; i < SQUARE_MIN_Y; i++) {
                        if (isBackBround(image, x, y + i, backBroundRGB, 5)) {
                            b = false;
                            break;
                        }
                    }
                    if (!b) {
                        continue;
                    }
                    return new int[] { x, y };
                }
            }
        }
        return null;
    }

    /**获取XY最大最小值*/
    public static int[] getMaxMinXY(BufferedImage image, int[] startPoint, int[] topPoint) {
        此处省略..................
        详情请到CSDN下载  http://download.csdn.net/download/lzlrl/10242212
        return new int[] { (maxX + minX) / 2, (maxY + minY) / 2, topX, topY, minX, minY, maxX, maxY };
    }

    /**找白点 为目标点*/
    public static int[] getWhitePoint(BufferedImage image, int[] topPoint) {
        // 先找白点 , 菱形音乐播放器最宽
        for (int i = topPoint[0]; i < topPoint[0] + TOP_WRITE_X; i++) {
            for (int j = topPoint[1]; j < topPoint[1] + TOP_WRITE_Y; j++) {
                int[] whitePoint = isWhitePoint(image, i, j);
                // 判断白点,如果有连续击中的白点,直接返回白点坐标
                if (whitePoint != null) {
                    return whitePoint;
                }
            }
        }
        return null;
    }

    /**判断白点 白点Y长度22 X长度38, 只判断Y轴不准确,再加X轴**/
    public static int[] isWhitePoint(BufferedImage image, int x, int y) {
        // 循环Y 向下找20个点的颜色,如果这20个点都是白色,并且这20个点上下不是白色,则为白点
        for (int i = y, num = 3, num2 = WRITE_Y + 3; i <= y + WRITE_Y - 2; i++, num++, num2--) {
            // 判断当前点不上白点则返回
            int[] myRGB = getMyRGB(image, x + 2, i);
            int r = myRGB[0];
            int g = myRGB[1];
            int b = myRGB[2];
            // 白点的颜色RGB为245 判断 Y向下22个点如果有不是白色的直接返回
            if (!(r == 245 && g == 245 && b == 245)) {
                return null;
            }
            // 判断白点圆圈上面第3个点是白点则返回
            int[] myRGB2 = getMyRGB(image, x + 2, i - num);
            int r2 = myRGB2[0];
            int g2 = myRGB2[1];
            int b2 = myRGB2[2];
            // 判断白点圆圈下面第3个点是白点则返回
            int[] myRGB3 = getMyRGB(image, x + 2, i + num2);
            int r3 = myRGB3[0];
            int g3 = myRGB3[1];
            int b3 = myRGB3[2];
            // 判断Y轴上这22个点外的第三个点是白色则返回
            if ((r2 == 245 && g2 == 245 && b2 == 245) || r3 == 245 && g3 == 245 && b3 == 245) {
                return null;
            }
        }

        // 有竖条为白色的刚好是22个像素(药瓶), 循环X 向左右找15个点的颜色,如果这15个点都是白色则为白点
        for (int i = x - (WRITE_X - 13); i <= x + (WRITE_X - 13); i++) {
            int[] myRGB = getMyRGB(image, i, y + 10);
            int r = myRGB[0];
            int g = myRGB[1];
            int b = myRGB[2];
            if (!(r == 245 && g == 245 && b == 245)) {
                return null;
            }
        }
        // 白点的中心点为 X+2,Y+(22/2)
        return new int[] { x + 2, y + 11, 0, 0, 0, 0, 0, 0 };
    }

    /** 找终点 */
    /**
     1.取背景色(很重要,他决定了顶点)
     2.找到顶点 (没有顶点,一切免谈)
     3.从顶点颜色开始,到背景色结束, 找和顶点颜色一样的最大(顶点往右)最小(顶点往左)坐标
     4.计算中心点,最大加最小除以二
     5.判断是否找到中心点,如果没找到,则取顶点往下位移50或者20的坐标
     */
    @SuppressWarnings("unused")
    public static int[] findEndPoint(BufferedImage image, int[] resXY) {
        // 顶点
        int topX = resXY[2];
        int topY = resXY[3];
        // 获取XY最大最小值
        int minX = resXY[4];
        int minY = resXY[5];
        int maxX = resXY[6];
        int maxY = resXY[7];

        // 判断药瓶 药瓶顶点颜色为纯白色
        // int[] topRGB = getMyRGB(image, topX, topY);
        // if (topRGB[0] == 255 && topRGB[0] == topRGB[1] && topRGB[0] == topRGB[2]) {
        // // 判断药瓶顶点Y正下方加130颜色 如果是这个,则顶点往下加30,101, 135, 164为药瓶下面蓝色
        // if (isRange(image, topX, topY + 130, 101, 135, 164, 5)) {
        // System.out.println("----------找到药瓶!!!");
        // return new int[] { topX + 8, topY + 26, 0, 0, 0, 0, 0 , 0 };
        // }
        // }

        // 终极办法防止未知情况,X最大最小不能超过460不能小于底座80 Y最大最小不能超过290不能小于底座40
        if (false) {
        } else if (minX - topX > SQUARE_MAX_X / 2 + 20) {
            resXY[0] = topX;
            resXY[1] = maxY;
            System.out.println("'\t\t\t------------左X过大(minX - topX)= " + (minX - topX));
        } else if (topX - minX < BODY_X / 2 - 18) {
            resXY[0] = topX;
            resXY[1] = minY;
            System.out.println("'\t\t\t------------左X过小(topX - minX)= " + (topX - minX));
        } else if (minY - topY > SQUARE_MAX_Y / 2) {
            resXY[0] = topX;
            resXY[1] = maxY;
            System.out.println("'\t\t\t------------左Y过大(minY - topY)= " + (minY - topY));
        } else if (minY - topY < SQUARE_MIN_Y / 2 - 4) {
            resXY[0] = topX;
            resXY[1] = minY;
            System.out.println("'\t\t\t------------左Y过小(minY - topY)= " + (minY - topY));
        }
        if (maxX - topX > SQUARE_MAX_X / 2 + 40) {
            resXY[0] = topX;
            resXY[1] = minY;
            System.out.println("'\t\t\t------------右X过大(maxX - topX)=" + (maxX - topX));
        } else if (maxX - topX < SQUARE_MIN_Y / 2 - 4) {
            resXY[0] = topX;
            resXY[1] = maxY;
            System.out.println("'\t\t\t------------右X过小(maxX - topX)= " + (maxX - topX));
        } else if (maxY - topY > SQUARE_MAX_Y / 2 + 10) {
            resXY[0] = topX;
            resXY[1] = minY;
            System.out.println("'\t\t\t------------右Y过大(maxY - topY)= " + (maxY - topY));
        } else if (maxY - topY < BODY_X / 2 - 20) {
            resXY[0] = topX;
            resXY[1] = minY;
            System.out.println("'\t\t\t------------右Y过小(maxY - topY)= " + (maxY - topY));
        }
        return resXY;
    }

    /** 发送按压屏幕指令 */
    public static void press(int pressTime) throws IOException {
        Random random = new Random();
        int pressX = PRESS_X + random.nextInt(170);
        int pressY = PRESS_Y + random.nextInt(200);
        int pressX2 = PRESS_X + random.nextInt(170);
        int pressY2 = PRESS_Y + random.nextInt(200);
        execute(String.format("adb shell input swipe %d %d %d %d %d", pressX, pressY, pressX2, pressY2, pressTime));
    }

    /** 发送截图拉取图片指令 */
    public static void pullImg(File file) throws IOException, InterruptedException {
        execute("adb shell /system/bin/screencap -p /sdcard/img.png");
        execute("adb pull /sdcard/img.png " + file.getAbsolutePath());
    }

    /** 加载图片 */
    public static BufferedImage getImage(File file) {
        BufferedImage image = null;
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            image = ImageIO.read(in);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return image;
    }

    /** 获取指定坐标的RGB值 */
    public static int[] getMyRGB(BufferedImage image, int x, int y) {
        try {
            int pixel = image.getRGB(x, y);
            int r = (pixel & 0xff0000) >> 16;
            int g = (pixel & 0xff00) >> 8;
            int b = (pixel & 0xff);
            return new int[] { r, g, b };
        } catch (Exception e) {
            System.out.println("获取RGB异常!!!" + x + ":" + y);
            e.printStackTrace();
        }
        return new int[] { 0, 0, 0 };
    }

    /** 获取指定坐标的RGB值是否在范围 t为误差值 */
    public static boolean isRange(BufferedImage image, int x, int y, int r, int g, int b, int e) {
        int[] myRGB = getMyRGB(image, x, y);
        int r2 = myRGB[0];
        int g2 = myRGB[1];
        int b2 = myRGB[2];
        // System.out.println(x + "," + y + ":" + r2 + "," + g2 + "," + b2);
        return r2 >= r - e && r2 <= r + e && g2 >= g - e && g2 <= g + e && b2 >= b - e && b2 <= b + e;
        // return Math.sqrt(Math.pow((r2 - r), 2) + Math.pow((g2 - g), 2) + Math.pow((b2 - b), 2)) > e;
    }

    /** 判断是否在背景色范围 t为误差值*/
    public static boolean isBackBround(BufferedImage image, int x, int y, int[] rgb, int e) {
        int r, g, b, r1, g1, b1, r2, g2, b2, minR, maxR, minG, maxG, minB, maxB;
        // 需要判断的颜色
        int[] myRGB = getMyRGB(image, x, y);
        r = myRGB[0];
        g = myRGB[1];
        b = myRGB[2];
        r1 = rgb[0];
        g1 = rgb[1];
        b1 = rgb[2];
        r2 = rgb[3];
        g2 = rgb[4];
        b2 = rgb[5];
        minR = Math.min(r1, r2) - e;
        maxR = Math.max(r1, r2) + e;
        minG = Math.min(g1, g2) - e;
        maxG = Math.max(g1, g2) + e;
        minB = Math.min(b1, b2) - e;
        maxB = Math.max(b1, b2) + e;
        return r >= minR && r <= maxR && g >= minG && g <= maxG && b >= minB && b <= maxB;
    }

    /** 执行ADB命令 */
    private static void execute(String command) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(command);
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("执行ADB异常!!! " + command);
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    /** 给图片在图上标注起点终点   */
    public static void drawImage(BufferedImage image, File file, int[] startPoint, int[] endPoint, String message) {
        Graphics2D g = image.createGraphics();
        g.setColor(new Color(255, 0, 0));// 255, 128, 255
        g.setBackground(Color.white);
        g.setFont(new Font("微软雅黑", Font.PLAIN, 40)); // 字体 字型 字号
        g.drawLine(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
        g.drawString(message, (startPoint[0] + endPoint[0]) / 2, (startPoint[1] + (startPoint[1] + endPoint[1]) / 2) / 2);
        g.drawString("+", startPoint[0] - 15, startPoint[1] + 13);
        g.drawString("+", endPoint[0] - 15, endPoint[1] + 13);
        if (endPoint[6] > 0) {
            g.drawString(".", endPoint[2] - 4, endPoint[3] + 3);
            g.drawString(".", endPoint[4] - 4, endPoint[5] + 3);
            g.drawString(".", endPoint[6] - 4, endPoint[7] + 3);
        }
        g.dispose();
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file.getAbsolutePath());
            ImageIO.write(image, "png", out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}