liuyuqi-dellpc 1 year ago
parent
commit
44e98de2cc

+ 6 - 0
README.md

@@ -2,6 +2,12 @@
 
 微信跳一跳助手,基于OpenCV识别图像计算距离和长按时间,adb shell模拟按键。
 
+## Usage
+
+1、下载adb 本项目jar包或者exe。
+2、手机开启USB调试,连接电脑,运行adb devices,确认手机已经连接。
+3、运行项目即可
+
 ## Develop
 
 打包成exe,集成adb:

+ 84 - 0
java/src/com/skyline/wxjumphack/BottleFinder.java

@@ -0,0 +1,84 @@
+package com.skyline.wxjumphack;
+
+import java.awt.image.BufferedImage;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * 瓶子的下一步位置计算
+ * Created by chenliang on 2017/12/31.
+ */
+public class BottleFinder {
+
+    public static final int TARGET = 255;
+
+    public int[] find(BufferedImage image, int i, int j) {
+        if (image == null) {
+            return null;
+        }
+
+        int[] ret = new int[6];
+        ret[0] = i;
+        ret[1] = j;
+        ret[2] = Integer.MAX_VALUE;
+        ret[3] = Integer.MAX_VALUE;
+        ret[4] = Integer.MIN_VALUE;
+        ret[5] = Integer.MAX_VALUE;
+
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        boolean[][] vMap = new boolean[width][height];
+        Queue<int[]> queue = new ArrayDeque<>();
+        int[] pos = {i, j};
+        queue.add(pos);
+
+        while (!queue.isEmpty()) {
+            pos = queue.poll();
+             i = pos[0];
+             j = pos[1];
+            if (i < 0 || i >= width || j < 0 || j > height || vMap[i][j]) {
+                continue;
+            }
+            vMap[i][j] = true;
+            int pixel = image.getRGB(i, j);
+            int r = (pixel & 0xff0000) >> 16;
+            int g = (pixel & 0xff00) >> 8;
+            int b = (pixel & 0xff);
+            if (r == TARGET && g == TARGET && b == TARGET) {
+                //System.out.println("("+i+", "+j+")");
+                if (i < ret[2]) {
+                    ret[2] = i;
+                    ret[3] = j;
+                } else if (i == ret[2] && j < ret[3]) {
+                    ret[2] = i;
+                    ret[3] = j;
+                }
+                if (i > ret[4]) {
+                    ret[4] = i;
+                    ret[5] = j;
+                } else if (i == ret[4] && j < ret[5]) {
+                    ret[4] = i;
+                    ret[5] = j;
+                }
+                if (j < ret[1]) {
+                    ret[0] = i;
+                    ret[1] = j;
+                }
+                queue.add(buildArray(i - 1, j));
+                queue.add(buildArray(i + 1, j));
+                queue.add(buildArray(i, j - 1));
+                queue.add(buildArray(i, j + 1));
+            }
+        }
+
+        return ret;
+    }
+
+    public static int[] buildArray(int i, int j) {
+        int[] ret = {i, j};
+        return ret;
+    }
+
+
+}

+ 103 - 0
java/src/com/skyline/wxjumphack/Hack.java

@@ -0,0 +1,103 @@
+package com.skyline.wxjumphack;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.Random;
+
+/**
+ * Created by chenliang on 2018/1/1.
+ */
+public class Hack {
+
+
+    static final String ADB_PATH = "D:/Program-Files/android-sdk-windows/platform-tools/adb.exe";
+
+    /**
+     * 弹跳系数,现在已经会自动适应各种屏幕,请不要修改。
+     */
+    static final double JUMP_RATIO = 1.390f;
+
+    private static Random RANDOM = new Random();
+
+    public static void main(String... strings) {
+        String root = Hack.class.getResource("/").getPath();
+        System.out.println("root: " + root);
+        File srcDir = new File(root, "imgs/input");
+        srcDir.mkdirs();
+        System.out.println("srcDir: " + srcDir.getAbsolutePath());
+        MyPosFinder myPosFinder = new MyPosFinder();
+        NextCenterFinder nextCenterFinder = new NextCenterFinder();
+        WhitePointFinder whitePointFinder = new WhitePointFinder();
+        int total = 0;
+        int centerHit = 0;
+        double jumpRatio = 0;
+        for (int i = 0; i < 5000; i++) {
+            try {
+                total++;
+                File file = new File(srcDir, i + ".png");
+                if (file.exists()) {
+                    file.deleteOnExit();
+                }
+                Process process = Runtime.getRuntime().exec(ADB_PATH + " shell /system/bin/screencap -p /sdcard/screenshot.png");
+                process.waitFor();
+                process = Runtime.getRuntime().exec(ADB_PATH + " pull /sdcard/screenshot.png " + file.getAbsolutePath());
+                process.waitFor();
+
+                System.out.println("screenshot, file: " + file.getAbsolutePath());
+                BufferedImage image = ImgLoader.load(file.getAbsolutePath());
+                if (jumpRatio == 0) {
+                    jumpRatio = JUMP_RATIO * 1080 / image.getWidth();
+                }
+                int[] myPos = myPosFinder.find(image);
+                if (myPos != null) {
+                    System.out.println("find myPos, succ, (" + myPos[0] + ", " + myPos[1] + ")");
+                    int[] nextCenter = nextCenterFinder.find(image, myPos);
+                    if (nextCenter == null || nextCenter[0] == 0) {
+                        System.err.println("find nextCenter, fail");
+                        break;
+                    } else {
+                        int centerX, centerY;
+                        int[] whitePoint = whitePointFinder.find(image, nextCenter[0] - 120, nextCenter[1], nextCenter[0] + 120, nextCenter[1] + 180);
+                        if (whitePoint != null) {
+                            centerX = whitePoint[0];
+                            centerY = whitePoint[1];
+                            centerHit++;
+                            System.out.println("find whitePoint, succ, (" + centerX + ", " + centerY + "), centerHit: " + centerHit + ", total: " + total);
+                        } else {
+                            if (nextCenter[2] != Integer.MAX_VALUE && nextCenter[4] != Integer.MIN_VALUE) {
+                                centerX = (nextCenter[2] + nextCenter[4]) / 2;
+                                centerY = (nextCenter[3] + nextCenter[5]) / 2;
+                            } else {
+                                centerX = nextCenter[0];
+                                centerY = nextCenter[1] + 48;
+                            }
+                        }
+                        System.out.println("find nextCenter, succ, (" + centerX + ", " + centerY + ")");
+                        int distance = (int) (Math.sqrt((centerX - myPos[0]) * (centerX - myPos[0]) + (centerY - myPos[1]) * (centerY - myPos[1])) * jumpRatio);
+                        System.out.println("distance: " + distance);
+                        int pressX = 400 + RANDOM.nextInt(100);
+                        int pressY = 500 + RANDOM.nextInt(100);
+                        String adbCommand = ADB_PATH + String.format(" shell input swipe %d %d %d %d %d", pressX, pressY, pressX, pressY, distance);
+                        System.out.println(adbCommand);
+                        Runtime.getRuntime().exec(adbCommand);
+                    }
+                } else {
+                    System.err.println("find myPos, fail");
+                    break;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                break;
+            }
+            try {
+                // sleep 随机时间,防止上传不了成绩
+                Thread.sleep(4_000 + RANDOM.nextInt(3000));
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+        }
+        System.out.println("centerHit: " + centerHit + ", total: " + total);
+    }
+
+}

+ 81 - 0
java/src/com/skyline/wxjumphack/HackTest.java

@@ -0,0 +1,81 @@
+package com.skyline.wxjumphack;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+
+/**
+ * Created by chenliang on 2018/1/1.
+ */
+public class HackTest {
+
+
+    public static void main(String... strings) throws IOException {
+        HackTest t = new HackTest();
+        String root = t.getClass().getResource("/").getPath();
+        System.out.println("root: " + root);
+        String imgsSrc = root + "imgs/input";
+        String imgsDesc = root + "imgs/output";
+        File srcDir = new File(imgsSrc);
+        System.out.println(srcDir);
+        MyPosFinder myPosFinder = new MyPosFinder();
+        NextCenterFinder nextCenterFinder = new NextCenterFinder();
+        WhitePointFinder whitePointFinder = new WhitePointFinder();
+
+        long cost = 0;
+        for (File file : srcDir.listFiles()) {
+            System.out.println(file);
+            BufferedImage img = ImgLoader.load(file.getAbsolutePath());
+            int[] myPos = myPosFinder.find(img);
+            int[] nextCenter = nextCenterFinder.find(img, myPos);
+            if (nextCenter == null || nextCenter[0] == 0) {
+                System.err.println("find nextCenter, fail");
+                continue;
+            } else {
+                int centerX, centerY;
+                int[] whitePoint = whitePointFinder.find(img, nextCenter[0] - 120, nextCenter[1], nextCenter[0] + 120, nextCenter[1] + 180);
+                if (whitePoint != null) {
+                    centerX = whitePoint[0];
+                    centerY = whitePoint[1];
+                    System.out.println("find whitePoint, succ, (" + centerX + ", " + centerY + ")");
+                } else {
+                    if (nextCenter[2] != Integer.MAX_VALUE && nextCenter[4] != Integer.MIN_VALUE) {
+                        centerX = (nextCenter[2] + nextCenter[4]) / 2;
+                        centerY = (nextCenter[3] + nextCenter[5]) / 2;
+                    } else {
+                        centerX = nextCenter[0];
+                        centerY = nextCenter[1] + 48;
+                    }
+                }
+                System.out.println("find nextCenter, succ, (" + centerX + ", " + centerY + ")");
+                BufferedImage desc = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
+                Graphics g = desc.getGraphics();
+                g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
+                g.setColor(Color.RED);
+                g.fillRect(myPos[0] - 5, myPos[1] - 5, 10, 10);
+                g.setColor(Color.GREEN);
+                g.fillRect(nextCenter[0] - 5, nextCenter[1] - 5, 10, 10);
+                g.fillRect(nextCenter[2] - 5, nextCenter[3] - 5, 10, 10);
+                g.fillRect(nextCenter[4] - 5, nextCenter[5] - 5, 10, 10);
+                g.setColor(Color.BLUE);
+                g.fillRect(centerX - 5, centerY - 5, 10, 10);
+                File descFile = new File(imgsDesc, file.getName());
+                if (!descFile.exists()) {
+                    descFile.mkdirs();
+                    descFile.createNewFile();
+                }
+                ImageIO.write(desc, "png", descFile);
+            }
+
+        }
+        System.out.println("avg time cost: " + (cost / srcDir.listFiles().length / 1_000_000));
+
+    }
+
+}

+ 28 - 0
java/src/com/skyline/wxjumphack/ImgLoader.java

@@ -0,0 +1,28 @@
+package com.skyline.wxjumphack;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by chenliang on 2017/12/31.
+ */
+public class ImgLoader {
+
+    public static BufferedImage load(String path) throws IOException {
+        BufferedImage image = null;
+        InputStream is = null;
+        try {
+            is = new BufferedInputStream(new FileInputStream(path));
+            image = ImageIO.read(is);
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+        }
+        return image;
+    }
+}

+ 84 - 0
java/src/com/skyline/wxjumphack/MyPosFinder.java

@@ -0,0 +1,84 @@
+package com.skyline.wxjumphack;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Created by chenliang on 2017/12/31.
+ */
+public class MyPosFinder {
+
+    public static final int R_TARGET = 40;
+
+    public static final int G_TARGET = 43;
+
+    public static final int B_TARGET = 86;
+
+    public int[] find(BufferedImage image) {
+        if (image == null) {
+            return null;
+        }
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        int[] ret = {0, 0};
+        int maxX = Integer.MIN_VALUE;
+        int minX = Integer.MAX_VALUE;
+        int maxY = Integer.MIN_VALUE;
+        int minY = Integer.MAX_VALUE;
+        for (int i = 0; i < width; i++) {
+            for (int j = height / 4; j < height * 3 / 4; j++) {
+                int pixel = image.getRGB(i, j);
+                int r = (pixel & 0xff0000) >> 16;
+                int g = (pixel & 0xff00) >> 8;
+                int b = (pixel & 0xff);
+                if (ToleranceHelper.match(r, g, b, R_TARGET, G_TARGET, B_TARGET, 16)) {
+                    maxX = Integer.max(maxX, i);
+                    minX = Integer.min(minX, i);
+                    maxY = Integer.max(maxY, j);
+                    minY = Integer.min(minY, j);
+                }
+            }
+        }
+        ret[0] = (maxX + minX) / 2 +3;
+        ret[1] = maxY;
+        System.out.println(maxX + ", " + minX);
+        System.out.println("pos, x: " + ret[0] + ", y: " + ret[1]);
+        return ret;
+    }
+
+    public static void main(String... strings) throws IOException {
+        MyPosFinder t = new MyPosFinder();
+        String root = t.getClass().getResource("/").getPath();
+        System.out.println("root: " + root);
+        String imgsSrc = root + "imgs/src";
+        String imgsDesc = root + "imgs/my_pos";
+        File srcDir = new File(imgsSrc);
+        System.out.println(srcDir);
+        long cost = 0;
+        for (File file : srcDir.listFiles()) {
+            if (!file.getName().endsWith(".png")) {
+                continue;
+            }
+            System.out.println(file);
+            BufferedImage img = ImgLoader.load(file.getAbsolutePath());
+            long t1 = System.nanoTime();
+            int[] pos = t.find(img);
+            long t2 = System.nanoTime();
+            cost += (t2 - t1);
+            BufferedImage desc = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
+            desc.getGraphics().drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null); // 绘制缩小后的图
+            desc.getGraphics().drawRect(pos[0] - 5, pos[1] - 5, 10, 10);
+            File descFile = new File(imgsDesc, file.getName());
+            if (!descFile.exists()) {
+                descFile.mkdirs();
+                descFile.createNewFile();
+            }
+            ImageIO.write(desc, "png", descFile);
+        }
+        System.out.println("avg time cost: " + (cost / srcDir.listFiles().length / 1_000_000));
+
+    }
+}

+ 214 - 0
java/src/com/skyline/wxjumphack/NextCenterFinder.java

@@ -0,0 +1,214 @@
+package com.skyline.wxjumphack;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+
+/**
+ * Created by chenliang on 2018/1/1.
+ */
+public class NextCenterFinder {
+
+    BottleFinder bottleFinder = new BottleFinder();
+
+    public int[] find(BufferedImage image, int[] myPos) {
+        if (image == null) {
+            return null;
+        }
+
+        int width = image.getWidth();
+        int height = image.getHeight();
+        int pixel = image.getRGB(0, 200);
+        int r1 = (pixel & 0xff0000) >> 16;
+        int g1 = (pixel & 0xff00) >> 8;
+        int b1 = (pixel & 0xff);
+        Map<Integer, Integer> map = new HashMap<>();
+        for (int i = 0; i < width; i++) {
+            pixel = image.getRGB(i, height - 1);
+            map.put(pixel, map.getOrDefault(pixel, 0) + 1);
+        }
+        int max = 0;
+        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
+            if (entry.getValue() > max) {
+                pixel = entry.getKey();
+                max = entry.getValue();
+            }
+        }
+        int r2 = (pixel & 0xff0000) >> 16;
+        int g2 = (pixel & 0xff00) >> 8;
+        int b2 = (pixel & 0xff);
+
+        int t = 16;
+
+        int minR = Integer.min(r1, r2) - t;
+        int maxR = Integer.max(r1, r2) + t;
+        int minG = Integer.min(g1, g2) - t;
+        int maxG = Integer.max(g1, g2) + t;
+        int minB = Integer.min(b1, b2) - t;
+        int maxB = Integer.max(b1, b2) + t;
+
+        System.out.println(minR + ", " + minG + ", " + minB);
+        System.out.println(maxR + ", " + maxG + ", " + maxB);
+
+        int[] ret = new int[6];
+        int targetR = 0, targetG = 0, targetB = 0;
+        boolean found = false;
+        for (int j = height / 4; j < myPos[1]; j++) {
+            for (int i = 0; i < width; i++) {
+                int dx = Math.abs(i - myPos[0]);
+                int dy = Math.abs(j - myPos[1]);
+                if (dy > dx) {
+                    continue;
+                }
+                pixel = image.getRGB(i, j);
+                int r = (pixel & 0xff0000) >> 16;
+                int g = (pixel & 0xff00) >> 8;
+                int b = (pixel & 0xff);
+                if (r < minR || r > maxR || g < minG || g > maxG || b < minB || b > maxB) {
+                    j = j + 2;
+                    ret[0] = i;
+                    ret[1] = j;
+                    System.out.println("top, x: " + i + ", y: " + j);
+                    for (int k = 0; k < 5; k++) {
+                        pixel = image.getRGB(i, j + k);
+                        System.out.println(pixel);
+                        targetR += (pixel & 0xff0000) >> 16;
+                        targetG += (pixel & 0xff00) >> 8;
+                        targetB += (pixel & 0xff);
+                    }
+                    targetR /= 5;
+                    targetG /= 5;
+                    targetB /= 5;
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+
+        if (targetR == BottleFinder.TARGET && targetG == BottleFinder.TARGET && targetB == BottleFinder.TARGET) {
+            return bottleFinder.find(image, ret[0], ret[1]);
+        }
+
+        boolean[][] matchMap = new boolean[width][height];
+        boolean[][] vMap = new boolean[width][height];
+        ret[2] = Integer.MAX_VALUE;
+        ret[3] = Integer.MAX_VALUE;
+        ret[4] = Integer.MIN_VALUE;
+        ret[5] = Integer.MAX_VALUE;
+
+        Queue<int[]> queue = new ArrayDeque<>();
+        queue.add(ret);
+        while (!queue.isEmpty()) {
+            int[] item = queue.poll();
+            int i = item[0];
+            int j = item[1];
+//            int dx = Math.abs(i - myPos[0]);
+//            int dy = Math.abs(j - myPos[1]);
+//            if (dy > dx) {
+//                continue;
+//            }
+            if (j >= myPos[1]) {
+                continue;
+            }
+
+            if (i < Integer.max(ret[0] - 300, 0) || i >= Integer.min(ret[0] + 300, width) || j < Integer.max(0, ret[1] - 400) || j >= Integer.max(height, ret[1] + 400) || vMap[i][j]) {
+                continue;
+            }
+            vMap[i][j] = true;
+            pixel = image.getRGB(i, j);
+            int r = (pixel & 0xff0000) >> 16;
+            int g = (pixel & 0xff00) >> 8;
+            int b = (pixel & 0xff);
+            matchMap[i][j] = ToleranceHelper.match(r, g, b, targetR, targetG, targetB, 16);
+//            if (i == ret[0] && j == ret[1]) {
+//                System.out.println(matchMap[i][j]);
+//            }
+            if (matchMap[i][j]) {
+                if (i < ret[2]) {
+                    ret[2] = i;
+                    ret[3] = j;
+                } else if (i == ret[2] && j < ret[3]) {
+                    ret[2] = i;
+                    ret[3] = j;
+                }
+                if (i > ret[4]) {
+                    ret[4] = i;
+                    ret[5] = j;
+                } else if (i == ret[4] && j < ret[5]) {
+                    ret[4] = i;
+                    ret[5] = j;
+                }
+                if (j < ret[1]) {
+                    ret[0] = i;
+                    ret[1] = j;
+                }
+                queue.add(buildArray(i - 1, j));
+                queue.add(buildArray(i + 1, j));
+                queue.add(buildArray(i, j - 1));
+                queue.add(buildArray(i, j + 1));
+            }
+        }
+
+        System.out.println("left, x: " + ret[2] + ", y: " + ret[3]);
+        System.out.println("right, x: " + ret[4] + ", y: " + ret[5]);
+
+        return ret;
+    }
+
+    public static int[] buildArray(int i, int j) {
+        int[] ret = {i, j};
+        return ret;
+    }
+
+    public static void main(String... strings) throws IOException {
+        //  int[] excepted = {0, 0};
+        NextCenterFinder t = new NextCenterFinder();
+        String root = t.getClass().getResource("/").getPath();
+        System.out.println("root: " + root);
+        String imgsSrc = root + "imgs/src";
+        String imgsDesc = root + "imgs/next_center";
+        File srcDir = new File(imgsSrc);
+        System.out.println(srcDir);
+        MyPosFinder myPosFinder = new MyPosFinder();
+        long cost = 0;
+        for (File file : srcDir.listFiles()) {
+            System.out.println(file);
+            BufferedImage img = ImgLoader.load(file.getAbsolutePath());
+            long t1 = System.nanoTime();
+            int[] myPos = myPosFinder.find(img);
+            int[] pos = t.find(img, myPos);
+            long t2 = System.nanoTime();
+            cost += (t2 - t1);
+            BufferedImage desc = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
+            Graphics g = desc.getGraphics();
+            g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
+            g.setColor(Color.RED);
+            g.fillRect(pos[0] - 5, pos[1] - 5, 10, 10);
+            g.fillRect(pos[2] - 5, pos[3] - 5, 10, 10);
+            g.fillRect(pos[4] - 5, pos[5] - 5, 10, 10);
+            if (pos[2] != Integer.MAX_VALUE && pos[4] != Integer.MIN_VALUE) {
+                g.fillRect((pos[2] + pos[4]) / 2 - 5, (pos[3] + pos[5]) / 2 - 5, 10, 10);
+            } else {
+                g.fillRect(pos[0], pos[1] + 36, 10, 10);
+            }
+            File descFile = new File(imgsDesc, file.getName());
+            if (!descFile.exists()) {
+                descFile.mkdirs();
+                descFile.createNewFile();
+            }
+            ImageIO.write(desc, "png", descFile);
+        }
+        System.out.println("avg time cost: " + (cost / srcDir.listFiles().length / 1_000_000));
+
+    }
+
+}

+ 16 - 0
java/src/com/skyline/wxjumphack/ToleranceHelper.java

@@ -0,0 +1,16 @@
+package com.skyline.wxjumphack;
+
+/**
+ * Created by chenliang on 2017/12/31.
+ */
+public class ToleranceHelper {
+
+    public static boolean match(int r, int g, int b, int rt, int gt, int bt, int t) {
+        return r > rt - t &&
+                r < rt+ t &&
+                g > gt - t &&
+                g < gt + t &&
+                b > bt - t &&
+                b < bt + t;
+    }
+}

+ 86 - 0
java/src/com/skyline/wxjumphack/WhitePointFinder.java

@@ -0,0 +1,86 @@
+package com.skyline.wxjumphack;
+
+import java.awt.image.BufferedImage;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Created by chenliang on 2017/12/31.
+ */
+public class WhitePointFinder {
+
+    public static final int TARGET = 245;
+
+    public int[] find(BufferedImage image, int x1, int y1, int x2, int y2) {
+        if (image == null) {
+            return null;
+        }
+
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        x1 = Integer.max(x1, 0);
+        x2 = Integer.min(x2, width - 1);
+        y1 = Integer.max(y1, 0);
+        y2 = Integer.min(y2, height - 1);
+
+        for (int i = x1; i <= x2; i++) {
+            for (int j = y1; j <= y2; j++) {
+                int pixel = image.getRGB(i, j);
+                int r = (pixel & 0xff0000) >> 16;
+                int g = (pixel & 0xff00) >> 8;
+                int b = (pixel & 0xff);
+                if (r == TARGET && g == TARGET && b == TARGET) {
+                    boolean[][] vMap = new boolean[width][height];
+                    Queue<int[]> queue = new ArrayDeque<>();
+                    int[] pos = {i, j};
+                    queue.add(pos);
+                    int maxX = Integer.MIN_VALUE;
+                    int minX = Integer.MAX_VALUE;
+                    int maxY = Integer.MIN_VALUE;
+                    int minY = Integer.MAX_VALUE;
+                    while (!queue.isEmpty()) {
+                        pos = queue.poll();
+                        int x = pos[0];
+                        int y = pos[1];
+                        if (x < x1 || x > x2 || y < y1 || y > y2 || vMap[x][y]) {
+                            continue;
+                        }
+                        vMap[x][y] = true;
+                        pixel = image.getRGB(x, y);
+                        r = (pixel & 0xff0000) >> 16;
+                        g = (pixel & 0xff00) >> 8;
+                        b = (pixel & 0xff);
+                        if (r == TARGET && g == TARGET && b == TARGET) {
+                            maxX = Integer.max(maxX, x);
+                            minX = Integer.min(minX, x);
+                            maxY = Integer.max(maxY, y);
+                            minY = Integer.min(minY, y);
+                            queue.add(buildArray(x - 1, y));
+                            queue.add(buildArray(x + 1, y));
+                            queue.add(buildArray(x, y - 1));
+                            queue.add(buildArray(x, y + 1));
+                        }
+                    }
+
+                    System.out.println("whitePoint: " + maxX + ", " + minX + ", " + maxY + ", " + minY);
+                    if (maxX - minX <= 45 && maxX - minX >= 35 && maxY - minY <= 30 && maxY - minY >= 20) {
+                        int[] ret = {(minX + maxX) / 2, (minY + maxY) / 2};
+                        return ret;
+                    } else {
+                        return null;
+                    }
+
+                }
+            }
+        }
+        return null;
+    }
+
+    public static int[] buildArray(int i, int j) {
+        int[] ret = {i, j};
+        return ret;
+    }
+
+
+}

+ 0 - 0
main.py → python/main.py


+ 0 - 0
requirements.txt → python/requirements.txt


+ 0 - 0
wxjump/__init__.py → python/wxjump/__init__.py


+ 0 - 0
wxjump/wxjump.py → python/wxjump/wxjump.py


+ 21 - 0
start.bat

@@ -0,0 +1,21 @@
+@echo off
+REM ***************************************************************************
+REM @Contact :   liuyuqi.gov@msn.cn
+REM @Time    :   2023/10/09 20:06:43
+REM @Version :   1.0
+REM @License :   (C)Copyright 2019 liuyuqi.
+REM @Desc    :   可以手动设置 Java 环境变量
+REM %1 - ext_name
+REM %2 - characters replaced
+REM %3 - new characters
+REM ***************************************************************************
+
+if "%PATH_BASE%" == "" set PATH_BASE=%PATH%
+set PATH=%CD%;%PATH_BASE%;
+
+java -jar "%~dp0\wxjump.jar" %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+
+
+
+