diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 86f36165..b430fd8a 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -11,17 +11,18 @@ "使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题", "调用 images.requestScreenCapture 时用户取消授权可能导致应用崩溃的问题", "images 部分相关方法出现异常时 oneShot 标记功能失效的问题 _[`issue #372`](http://issues.autojs6.com/372)_", + "images 部分相关方法可能引发内存泄露的问题 _[`issue #372`](http://issues.autojs6.com/372)_", "Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_", "打包应用无法正常使用 Paddle OCR 与 Rapid OCR 功能的问题", "版本历史页面部分系统因字体差别导致统计数据显示不完整的问题", "ErrorDialogActivity 可能无法正常启动的问题 _[`issue #414`](http://issues.autojs6.com/414)_ _[`issue #340`](http://issues.autojs6.com/340#issuecomment-2973485826)_", - "错误报告页面复制详细信息功能失效的问题" + "崩溃报告页面复制详细信息功能失效的问题" ], "improvement": [ "http 模块相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_", "android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数", "内置模块相关方法实参类型的异常消息增加类型摘要信息", - "错误报告页面支持双指缩放调整字体大小并添加常用功能按钮" + "崩溃报告页面支持双指缩放调整字体大小并添加常用功能按钮" ], "dependency": [ "附加 Androidx Core (KTX) 版本 1.16.0", diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aab3828d..151b7a5b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -290,8 +290,8 @@ android:name="org.autojs.autojs.ui.settings.DeveloperOptionsActivity" android:theme="@style/AppTheme.Settings" /> - - + + referenceQueue = new ReferenceQueue<>(); - - static { - Executors.newFixedThreadPool(1).execute(() -> { - while (true) { - try { - NativeObjectReference nativeObjectReference = (NativeObjectReference) Cleaner.referenceQueue.remove(); - if (nativeObjectReference == null) { - continue; - } - instance.cleanup(nativeObjectReference); - } catch (InterruptedException e) { - /* Ignored. */ - } - break; - } - }); - } - - public void cleanup(NativeObjectReference nativeObjectReference) { - try { - pointer.decrementAndGet(); - RegisteredCleaners.registeredCleaners.remove(nativeObjectReference); - long pointer = nativeObjectReference.pointer; - if (pointer == 0L) return; - nativeObjectReference.cleaner.cleanup(pointer); - nativeObjectReference.pointer = 0L; - } catch (Throwable throwable) { - Log.w(Cleaner.class.getSimpleName(), "cleanup error: " + nativeObjectReference.pointer, throwable); - } - } - - public void cleanup(MonitorResource resource, ICleaner cleaner) { - resource.getPointer(); - NativeObjectReference resourceNativeCleaner = new NativeObjectReference<>(resource, referenceQueue, cleaner); - resourceNativeCleaner.pointer = resource.getPointer(); - resource.setNativeObjectReference(resourceNativeCleaner); - RegisteredCleaners.registeredCleaners.add(resourceNativeCleaner); - pointer.incrementAndGet(); - } - -} diff --git a/app/src/main/java/org/autojs/autojs/core/cleaner/ICleaner.java b/app/src/main/java/org/autojs/autojs/core/cleaner/ICleaner.java deleted file mode 100644 index c4ca8c7c..00000000 --- a/app/src/main/java/org/autojs/autojs/core/cleaner/ICleaner.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.autojs.autojs.core.cleaner; - -/** - * Created by SuperMonster003 on Dec 22, 2023. - */ -// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 22, 2023. -public interface ICleaner { - - void cleanup(final long pointer); - -} diff --git a/app/src/main/java/org/autojs/autojs/core/cleaner/RegisteredCleaners.java b/app/src/main/java/org/autojs/autojs/core/cleaner/RegisteredCleaners.java deleted file mode 100644 index 2349ecb0..00000000 --- a/app/src/main/java/org/autojs/autojs/core/cleaner/RegisteredCleaners.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.autojs.autojs.core.cleaner; - -import org.autojs.autojs.core.ref.MonitorResource; -import org.autojs.autojs.core.ref.NativeObjectReference; - -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Created by SuperMonster003 on Dec 22, 2023. - */ -// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 22, 2023. -public final class RegisteredCleaners { - - public static final Set> registeredCleaners = Collections.newSetFromMap(new ConcurrentHashMap<>()); - -} diff --git a/app/src/main/java/org/autojs/autojs/core/image/ImageWrapper.kt b/app/src/main/java/org/autojs/autojs/core/image/ImageWrapper.kt index 854bacf2..a68c90db 100644 --- a/app/src/main/java/org/autojs/autojs/core/image/ImageWrapper.kt +++ b/app/src/main/java/org/autojs/autojs/core/image/ImageWrapper.kt @@ -9,8 +9,6 @@ import androidx.core.graphics.get import org.autojs.autojs.annotation.ScriptInterface import org.autojs.autojs.core.opencv.Mat import org.autojs.autojs.core.opencv.OpenCVHelper -import org.autojs.autojs.core.ref.MonitorResource -import org.autojs.autojs.core.ref.NativeObjectReference import org.autojs.autojs.pio.UncheckedIOException import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.Images @@ -24,7 +22,6 @@ import org.opencv.imgproc.Imgproc import java.io.FileNotFoundException import java.io.FileOutputStream import java.lang.ref.WeakReference -import java.util.concurrent.atomic.AtomicLong /** * Created by Stardust on Nov 25, 2017. @@ -32,14 +29,14 @@ import java.util.concurrent.atomic.AtomicLong * Transformed by SuperMonster003 on May 16, 2023. */ // @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 20, 2023. -open class ImageWrapper : Shootable, MonitorResource { +open class ImageWrapper : Shootable { private var mScriptRuntime: ScriptRuntime private var mMat: Mat? = null private var mBgrMat: Mat? = null private var mBitmap: Bitmap? = null - private var mRef: NativeObjectReference? = null + private var mMediaImage: Image? = null private var mPlane: Image.Plane? = null private var mWidth = 0 @@ -47,12 +44,6 @@ open class ImageWrapper : Shootable, MonitorResource { private var mIsRecycled = false private var mIsOneShot = false - private var mId = 0L - private val mNextId = AtomicLong() - - var mediaImage: Image? = null - private set - val width get() = mWidth.also { ensureNotRecycled() } @@ -71,10 +62,7 @@ open class ImageWrapper : Shootable, MonitorResource { val bitmap = createBitmap(mat.width(), mat.height()).also { mBitmap = it } Utils.matToBitmap(mat, bitmap) } else { - val mediaImage = mediaImage - if (mediaImage != null) { - mBitmap = toBitmap(mediaImage) - } + mMediaImage?.let { mBitmap = toBitmap(it) } } } return mBitmap ?: throw Exception("Bitmap of ImageWrapper should never be null") @@ -93,7 +81,7 @@ open class ImageWrapper : Shootable, MonitorResource { Utils.bitmapToMat(bitmap, newMat) return newMat } - if (mediaImage != null) { + if (mMediaImage != null) { val plane = plane ?: throw AssertionError("Image plain is null") plane.buffer.position(0) return Mat(mHeight, mWidth, CvType.CV_8UC4, plane.buffer, plane.rowStride.toLong()).also { mMat = it } @@ -111,13 +99,12 @@ open class ImageWrapper : Shootable, MonitorResource { private set(plane) { mPlane = plane } - get() = mPlane ?: mediaImage?.planes?.get(0) + get() = mPlane ?: mMediaImage?.planes?.get(0) constructor(scriptRuntime: ScriptRuntime, width: Int, height: Int) : this(scriptRuntime, createBitmap(width, height)) constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap) { mScriptRuntime = scriptRuntime - mId = mNextId.incrementAndGet() mBitmap = bitmap.also { addToList(it) } mWidth = bitmap.width mHeight = bitmap.height @@ -125,7 +112,6 @@ open class ImageWrapper : Shootable, MonitorResource { constructor(scriptRuntime: ScriptRuntime, mat: Mat) { mScriptRuntime = scriptRuntime - mId = mNextId.incrementAndGet() mMat = mat.also { addToList(it) } mWidth = mat.cols() mHeight = mat.rows() @@ -133,7 +119,6 @@ open class ImageWrapper : Shootable, MonitorResource { constructor(scriptRuntime: ScriptRuntime, mat: org.opencv.core.Mat) { mScriptRuntime = scriptRuntime - mId = mNextId.incrementAndGet() mMat = when (mat.nativeObj != 0L) { true -> Mat(mat.nativeObj) else -> Mat(mat.rows(), mat.cols(), mat.type()) @@ -144,7 +129,6 @@ open class ImageWrapper : Shootable, MonitorResource { constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap, mat: Mat?) { mScriptRuntime = scriptRuntime - mId = mNextId.incrementAndGet() mMat = mat?.also { addToList(it) } mBitmap = bitmap.also { addToList(it) } mWidth = bitmap.width @@ -153,8 +137,7 @@ open class ImageWrapper : Shootable, MonitorResource { constructor(scriptRuntime: ScriptRuntime, mediaImage: Image) { mScriptRuntime = scriptRuntime - mId = mNextId.incrementAndGet() - this.mediaImage = mediaImage.also { addToList(it) } + mMediaImage = mediaImage.also { addToList(it) } mWidth = mediaImage.width mHeight = mediaImage.height } @@ -269,12 +252,10 @@ open class ImageWrapper : Shootable, MonitorResource { OpenCVHelper.release(it) mBgrMat = null } - mediaImage?.let { + mMediaImage?.let { it.close() - mediaImage = null - } - mRef?.let { - it.pointer = 0L + mMediaImage = null + mPlane = null } mIsRecycled = true } @@ -301,12 +282,6 @@ open class ImageWrapper : Shootable, MonitorResource { } } - override fun getPointer() = mId - - override fun setNativeObjectReference(reference: NativeObjectReference) { - mRef = reference - } - companion object { private val imageList = ArrayList>() diff --git a/app/src/main/java/org/autojs/autojs/core/image/TemplateMatching.java b/app/src/main/java/org/autojs/autojs/core/image/TemplateMatching.java index c24c0284..c6ecd0ca 100644 --- a/app/src/main/java/org/autojs/autojs/core/image/TemplateMatching.java +++ b/app/src/main/java/org/autojs/autojs/core/image/TemplateMatching.java @@ -158,32 +158,28 @@ public class TemplateMatching { Mat currentTemplate = getPyramidDownAtLevel(template, level); Mat transparentMask = useTransparentMask ? createTransparentMask(currentTemplate) : null; - boolean shouldStop; - - Label_Check_Should_Stop: - { - // 如果在上一轮中没有匹配到图片, 则考虑是否退出匹配 - if (previousMatchResult.isEmpty()) { - // 如果不是第一次匹配, 并且不满足shouldContinueMatching的条件, 则直接退出匹配 - if (!isFirstMatching && !shouldContinueMatching(level, selectPyramidLevel)) { - shouldStop = true; - break Label_Check_Should_Stop; - } - Mat matchResult = matchTemplate(src, currentTemplate, matchingMethod, transparentMask); - getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, null, finalMatchResult); - OpenCVHelper.release(matchResult); - } else { - for (Match match : previousMatchResult) { - // 根据上一轮的匹配点, 计算本次匹配的区域 - Rect roi = getROI(match.point, src, currentTemplate); - Mat m = new Mat(src, roi); - Mat matchResult = matchTemplate(m, currentTemplate, matchingMethod, transparentMask); - getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, roi, finalMatchResult); - OpenCVHelper.release(m); - OpenCVHelper.release(matchResult); - } + // 如果在上一轮中没有匹配到图片, 则考虑是否退出匹配 + if (previousMatchResult.isEmpty()) { + // 如果不是第一次匹配, 并且不满足shouldContinueMatching的条件, 则直接退出匹配 + if (!isFirstMatching && !shouldContinueMatching(level, selectPyramidLevel)) { + releaseIfNeeded(src, img); + releaseIfNeeded(currentTemplate, template); + OpenCVHelper.release(transparentMask); + break; + } + Mat matchResult = matchTemplate(src, currentTemplate, matchingMethod, transparentMask); + getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, null, finalMatchResult); + OpenCVHelper.release(matchResult); + } else { + for (Match match : previousMatchResult) { + // 根据上一轮的匹配点, 计算本次匹配的区域 + Rect roi = getROI(match.point, src, currentTemplate); + Mat m = new Mat(src, roi); + Mat matchResult = matchTemplate(m, currentTemplate, matchingMethod, transparentMask); + getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, roi, finalMatchResult); + OpenCVHelper.release(m); + OpenCVHelper.release(matchResult); } - shouldStop = false; } releaseIfNeeded(src, img); releaseIfNeeded(currentTemplate, template); @@ -191,26 +187,24 @@ public class TemplateMatching { logger.addSplit("level:" + level + ", result:" + previousMatchResult); - if (!shouldStop) { - // 把满足强阈值的点找出来, 加到最终结果列表 - if (!currentMatchResult.isEmpty()) { - Iterator iterator = currentMatchResult.iterator(); - while (iterator.hasNext()) { - Match match = iterator.next(); - if (match.similarity >= strictThreshold) { - pyrUp(match.point, level); - finalMatchResult.add(match); - iterator.remove(); - } - } - // 如果所有结果都满足强阈值, 则退出循环, 返回最终结果 - if (currentMatchResult.isEmpty()) { - break; + // 把满足强阈值的点找出来, 加到最终结果列表 + if (!currentMatchResult.isEmpty()) { + Iterator iterator = currentMatchResult.iterator(); + while (iterator.hasNext()) { + Match match = iterator.next(); + if (match.similarity >= strictThreshold) { + pyrUp(match.point, level); + finalMatchResult.add(match); + iterator.remove(); } } - previousMatchResult = currentMatchResult; - isFirstMatching = false; + // 如果所有结果都满足强阈值, 则退出循环, 返回最终结果 + if (currentMatchResult.isEmpty()) { + break; + } } + isFirstMatching = false; + previousMatchResult = currentMatchResult; } logger.addSplit("result:" + finalMatchResult); logger.dumpToLog(); diff --git a/app/src/main/java/org/autojs/autojs/core/opencv/Mat.java b/app/src/main/java/org/autojs/autojs/core/opencv/Mat.java index 1740f703..ce344112 100644 --- a/app/src/main/java/org/autojs/autojs/core/opencv/Mat.java +++ b/app/src/main/java/org/autojs/autojs/core/opencv/Mat.java @@ -1,10 +1,6 @@ package org.autojs.autojs.core.opencv; import androidx.annotation.NonNull; -import org.autojs.autojs.core.cleaner.Cleaner; -import org.autojs.autojs.core.cleaner.ICleaner; -import org.autojs.autojs.core.ref.MonitorResource; -import org.autojs.autojs.core.ref.NativeObjectReference; import org.opencv.core.CvType; import org.opencv.core.Range; import org.opencv.core.Rect; @@ -15,105 +11,80 @@ import org.opencv.imgproc.Imgproc; import java.lang.reflect.Method; import java.nio.ByteBuffer; -public class Mat extends org.opencv.core.Mat implements MonitorResource { - - public static final ICleaner MAT_CLEANER = new MatCleaner(null); +public class Mat extends org.opencv.core.Mat { private volatile boolean mReleased; - + private static final Method nClone = findMethod("n_clone", Long.TYPE); private static final Method nOnes = findMethod("n_ones", Integer.TYPE, Integer.TYPE, Integer.TYPE); private static final Method nRelease = findMethod("n_release", Long.TYPE); - - private NativeObjectReference mReference; public Mat() { super(); - init(); } public Mat(long addr) { super(addr); - init(); } public Mat(int rows, int cols, int type) { super(rows, cols, type); - init(); } public Mat(Size size, int type) { super(size, type); - init(); } public Mat(int rows, int cols, int type, Scalar s) { super(rows, cols, type, s); - init(); } public Mat(Size size, int type, Scalar s) { super(size, type, s); - init(); } public Mat(Mat m, Range rowRange, Range colRange) { super(m, rowRange, colRange); - init(); } public Mat(Mat m, Range rowRange) { super(m, rowRange); - init(); } public Mat(Mat m, Rect roi) { super(m, roi); - init(); } public Mat(int rows, int cols, int type, ByteBuffer data) { super(rows, cols, type, data); - init(); } public Mat(int rows, int cols, int type, ByteBuffer data, long step) { super(rows, cols, type, data, step); - init(); } public Mat(org.opencv.core.Mat opencvMat, Range rowRange) { super(opencvMat, rowRange); - init(); } public Mat(org.opencv.core.Mat opencvMat, Range rowRange, Range colRange) { super(opencvMat, rowRange, colRange); - init(); } public Mat(org.opencv.core.Mat opencvMat, Rect rect) { super(opencvMat, rect); - init(); } public Mat(org.opencv.core.Mat opencvMat, Range[] ranges) { super(opencvMat, ranges); - init(); } public Mat(int[] sizes, int type) { super(sizes, type); - init(); } public Mat(int[] sizes, int type, Scalar scalar) { super(sizes, type, scalar); - init(); - } - - private void init() { - Cleaner.instance.cleanup(this, MAT_CLEANER); } private static Method findMethod(final String s, final Class... array) { @@ -179,34 +150,19 @@ public class Mat extends org.opencv.core.Mat implements MonitorResource { return nRelease; } - @Override - public long getPointer() { - return super.nativeObj; - } - - @Override - public void setNativeObjectReference(final NativeObjectReference reference) { - mReference = reference; - } - - public String getPointerString() { - return Long.toString(super.nativeObj); - } - public boolean isReleased() { - return mReleased || mReference != null && mReference.pointer == 0L; + return mReleased; } @Override public void release() { - if (mReleased) return; - synchronized (this) { - if (mReleased) return; - mReleased = true; - if (mReference != null) { - mReference.pointer = 0L; + if (!mReleased) { + synchronized (this) { + if (!mReleased) { + super.release(); + mReleased = true; + } } - super.release(); } } diff --git a/app/src/main/java/org/autojs/autojs/core/opencv/MatCleaner.java b/app/src/main/java/org/autojs/autojs/core/opencv/MatCleaner.java deleted file mode 100644 index 345e1ced..00000000 --- a/app/src/main/java/org/autojs/autojs/core/opencv/MatCleaner.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.autojs.autojs.core.opencv; - -import org.autojs.autojs.core.cleaner.ICleaner; -import org.autojs.autojs.runtime.api.Images; - -/** - * Created by SuperMonster003 on Jan 5, 2024. - */ -// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Jan 5, 2024. -public class MatCleaner implements ICleaner { - - private MatCleaner() { - /* Empty body. */ - } - - public MatCleaner(Object object) { - this(); - } - - @Override - public void cleanup(long pointer) { - try { - Images.initOpenCvIfNeeded(); - Mat.n_release().invoke(null, pointer); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - -} diff --git a/app/src/main/java/org/autojs/autojs/core/opencv/MatOfPoint.java b/app/src/main/java/org/autojs/autojs/core/opencv/MatOfPoint.java index 5272f4c0..550d2b1c 100644 --- a/app/src/main/java/org/autojs/autojs/core/opencv/MatOfPoint.java +++ b/app/src/main/java/org/autojs/autojs/core/opencv/MatOfPoint.java @@ -1,62 +1,41 @@ package org.autojs.autojs.core.opencv; -import org.autojs.autojs.core.cleaner.Cleaner; -import org.autojs.autojs.core.ref.MonitorResource; -import org.autojs.autojs.core.ref.NativeObjectReference; import org.opencv.core.Point; /** * Modified by SuperMonster003 as of Jan 21, 2023. */ // @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 18, 2023. -public class MatOfPoint extends org.opencv.core.MatOfPoint implements MonitorResource { +public class MatOfPoint extends org.opencv.core.MatOfPoint { private volatile boolean mReleased = false; - private NativeObjectReference mReference; - public MatOfPoint() { - init(); + super(); } public MatOfPoint(long l) { super(l); - init(); } public MatOfPoint(org.opencv.core.Mat mat) { super(mat); - init(); } public MatOfPoint(Point... pointArray) { super(pointArray); - init(); - } - - private void init() { - Cleaner.instance.cleanup(this, Mat.MAT_CLEANER); } @Override public void release() { - if (mReleased) return; - synchronized (this) { - if (mReleased) return; - mReleased = true; - if (mReference != null) { - mReference.pointer = 0L; + if (!mReleased) { + synchronized (this) { + if (!mReleased) { + super.release(); + mReleased = true; + } } - super.release(); } } - public long getPointer() { - return nativeObj; - } - - public void setNativeObjectReference(NativeObjectReference reference) { - mReference = reference; - } - } diff --git a/app/src/main/java/org/autojs/autojs/core/ref/MonitorResource.java b/app/src/main/java/org/autojs/autojs/core/ref/MonitorResource.java deleted file mode 100644 index a2e5f559..00000000 --- a/app/src/main/java/org/autojs/autojs/core/ref/MonitorResource.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.autojs.autojs.core.ref; - -/** - * Created by SuperMonster003 on Dec 20, 2023. - */ -// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 20, 2023. -public interface MonitorResource { - - long getPointer(); - - void setNativeObjectReference(final NativeObjectReference reference); - -} diff --git a/app/src/main/java/org/autojs/autojs/core/ref/NativeObjectReference.java b/app/src/main/java/org/autojs/autojs/core/ref/NativeObjectReference.java deleted file mode 100644 index 61cff521..00000000 --- a/app/src/main/java/org/autojs/autojs/core/ref/NativeObjectReference.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.autojs.autojs.core.ref; - -import org.autojs.autojs.core.cleaner.ICleaner; - -import java.lang.ref.*; - -/** - * Created by SuperMonster003 on Dec 15, 2023. - */ -// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 15, 2023. -public final class NativeObjectReference extends PhantomReference { - - public final ICleaner cleaner; - public volatile long pointer; - - public NativeObjectReference(final T referent, final ReferenceQueue referenceQueue, final ICleaner cleaner) { - super(referent, referenceQueue); - this.cleaner = cleaner; - } - -} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/ImageFeatureMatching.java b/app/src/main/java/org/autojs/autojs/runtime/api/ImageFeatureMatching.java index a893bc43..d96cdeda 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/ImageFeatureMatching.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/ImageFeatureMatching.java @@ -4,10 +4,6 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.autojs.autojs.annotation.ScriptInterface; -import org.autojs.autojs.core.cleaner.Cleaner; -import org.autojs.autojs.core.cleaner.ICleaner; -import org.autojs.autojs.core.ref.MonitorResource; -import org.autojs.autojs.core.ref.NativeObjectReference; import org.autojs.autojs.util.ImageUtils; import org.opencv.calib3d.Calib3d; import org.opencv.core.Core; @@ -314,11 +310,10 @@ public final class ImageFeatureMatching { * A reusable bundle of feature-extraction results for a single image. * zh-CN: 单张图片的特征提取结果集合. */ - public static class FeatureMatchingDescriptor implements MonitorResource { + public static class FeatureMatchingDescriptor { private final Mat mDescriptors; private long mNativePtr; - private NativeObjectReference mRef; private final MatOfKeyPoint mKeyPoint; private final MatOfPoint2f mCorners; @@ -344,18 +339,12 @@ public final class ImageFeatureMatching { mNativePtr = descriptors.nativeObj; mKeyPoint = keyPoint; mCorners = corners; - Cleaner.instance.cleanup(this, SelfCleaner.INSTANCE); } public long getNativePtr() { return mNativePtr; } - @Override - public long getPointer() { - return mNativePtr; - } - public MatOfKeyPoint getKeyPoint() { return mKeyPoint; } @@ -367,20 +356,12 @@ public final class ImageFeatureMatching { public void release() { synchronized (this) { if (mNativePtr != 0L) { - SelfCleaner.INSTANCE.cleanup(mNativePtr); + releaseFeatureMatchingDescriptor(mNativePtr); mNativePtr = 0L; - if (mRef != null) { - mRef.pointer = 0L; - } } } } - @Override - public void setNativeObjectReference(NativeObjectReference ref) { - mRef = ref; - } - public void setNativePtr(long nativePtr) { mNativePtr = nativePtr; } @@ -389,23 +370,6 @@ public final class ImageFeatureMatching { return mCorners; } - public static class SelfCleaner implements ICleaner { - - public static SelfCleaner INSTANCE; - - static { - INSTANCE = new SelfCleaner(); - } - - private SelfCleaner() { - /* Empty body. */ - } - - @Override - public void cleanup(long pointer) { - releaseFeatureMatchingDescriptor(pointer); - } - } } /** diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java index 4df737de..97624d6a 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java @@ -628,7 +628,6 @@ public class Images { throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.findImage", "template")); } Mat src = image.getMat(); - boolean shouldReleaseMat = false; if (rect != null) { if (template.getWidth() > rect.width) { throw new Exception(mContext.getString(R.string.error_excessive_width_for_template_n_region, template.getWidth(), rect.width)); @@ -637,7 +636,6 @@ public class Images { throw new Exception(mContext.getString(R.string.error_excessive_height_for_template_n_region, template.getHeight(), rect.height)); } src = new Mat(src, rect); - shouldReleaseMat = true; } @Nullable org.opencv.core.Point point; @@ -645,10 +643,10 @@ public class Images { point = TemplateMatching.singleTemplateMatching( src, template.getMat(), - new TemplateMatching.Options(-1, weakThreshold, strictThreshold, maxLevel) + new TemplateMatching.Options(TemplateMatching.MATCHING_METHOD_NONE, weakThreshold, strictThreshold, maxLevel) ); } finally { - if (shouldReleaseMat) { + if (src != image.getMat()) { OpenCVHelper.release(src); } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt index 8ca2ef8d..388fcfda 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt @@ -760,14 +760,15 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt @RhinoRuntimeFunctionInterface fun concat(scriptRuntime: ScriptRuntime, args: Array): ImageWrapper = ensureArgumentsLengthInRange(args, 2..3) { val (oA, oB, direction) = it - val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA - require(imageA is ImageWrapper) { "Argument \"imageA\" ${imageA.jsBrief()} for images.concat must be a ImageWrapper" } - val imageB = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB - require(imageB is ImageWrapper) { - imageA.shoot() - "Argument \"imageB\" ${imageB.jsBrief()} for images.concat must be a ImageWrapper" - } + var imageA: ImageWrapper? = null + var imageB: ImageWrapper? = null try { + val imageARaw = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA + require(imageARaw is ImageWrapper) { "Argument \"imageA\" ${imageARaw.jsBrief()} for images.concat must be a ImageWrapper" } + imageA = imageARaw + val imageBRaw = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB + require(imageBRaw is ImageWrapper) { "Argument \"imageB\" ${imageBRaw.jsBrief()} for images.concat must be a ImageWrapper" } + imageB = imageBRaw initOpenCvIfNeeded() ApiImages.concat(scriptRuntime, imageA, imageB, directionToGravityToConcat(direction)) } finally { @@ -777,48 +778,55 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt @JvmStatic @RhinoRuntimeFunctionInterface - fun detectColor(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 4..6) { - val (o, color, x, y, threshold, algorithm) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectColor must be a ImageWrapper" } + fun detectColor(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 4..6) { argList -> + detectColorRhino(scriptRuntime, argList, ::detectColor.name) + } + + @JvmStatic + fun detectColorRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): Boolean { + val (o, color, x, y, threshold, algorithm) = args + var imageRef: ImageWrapper? = null try { + val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectColor must be a ImageWrapper" } + imageRef = image initOpenCvIfNeeded() val pixel = pixel(scriptRuntime, arrayOf(image, coerceIntNumber(x), coerceIntNumber(y))) - ColorDetector + return ColorDetector .get(Colors.toIntRhino(color), coerceString(algorithm, DEFAULT_COLOR_ALGORITHM), parseNumber(threshold, DEFAULT_COLOR_THRESHOLD)) .detectColor(Colors.redRhino(pixel).roundToInt(), Colors.greenRhino(pixel).roundToInt(), Colors.blueRhino(pixel).roundToInt()) } finally { - image.shoot() + ApiImages.shoot(imageRef) } } @Deprecated("Deprecated in Java", ReplaceWith("detectColor(image, color, x, y, threshold, algorithm)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun detectsColor(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 4..6) { - val (o) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectsColor must be a ImageWrapper" } - try { - initOpenCvIfNeeded() - detectColor(scriptRuntime, it) - } finally { - image.shoot() - } + fun detectsColor(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 4..6) { argList -> + @Suppress("DEPRECATION") + detectColorRhino(scriptRuntime, argList, ::detectsColor.name) } // @Reference to module __images__.js from Auto.js Pro 9.3.11 by SuperMonster003 on May 10, 2025. @JvmStatic @RhinoRuntimeFunctionInterface - fun detectMultiColors(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 5..6) { - val (o, x, y, firstColor, paths, options) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectMultiColors must be a ImageWrapper" } + fun detectMultiColors(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 5..6) { argList -> + detectMultiColorsRhino(scriptRuntime, argList, ::detectMultiColors.name) + } + + @JvmStatic + fun detectMultiColorsRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): Boolean { + val (o, x, y, firstColor, paths, options) = args + var imageRef: ImageWrapper? = null try { + val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectMultiColors must be a ImageWrapper" } + imageRef = image require(paths is NativeArray) { "Argument \"paths\" ${paths.jsBrief()} for images.detectMultiColors must be a JavaScript Array" } initOpenCvIfNeeded() val opt = options as? NativeObject ?: newNativeObject() - scriptRuntime.images.colorFinder.detectMultiColors( + return scriptRuntime.images.colorFinder.detectMultiColors( image, coerceIntNumber(x), coerceIntNumber(y), @@ -831,133 +839,140 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt }.toIntArray(), ) } finally { - image.shoot() + ApiImages.shoot(imageRef) } } @Deprecated("Deprecated in Java", ReplaceWith("detectMultiColors(image, x, y, firstColor, paths, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun detectsMultiColors(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 5..6) { - val (o, _, _, _, paths) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectMultiColors must be a ImageWrapper" } - try { - require(paths is NativeArray) { "Argument \"paths\" ${paths.jsBrief()} for images.detectMultiColors must be a JavaScript Array" } - initOpenCvIfNeeded() - detectMultiColors(scriptRuntime, it) - } finally { - image.shoot() - } + fun detectsMultiColors(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLengthInRange(args, 5..6) { argList -> + @Suppress("DEPRECATION") + detectMultiColorsRhino(scriptRuntime, argList, ::detectsMultiColors.name) } @JvmStatic @RhinoRuntimeFunctionInterface fun findPointByColor(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> - val (o, color, xOrOptions, y, width, height, threshold) = argList - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColor must be a ImageWrapper" } + findPointByColorRhino(scriptRuntime, argList, ::findPointByColor.name) + } + + @JvmStatic + fun findPointByColorRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String, overriddenThreshold: Int? = null): OpencvPoint? { + val (o, color, xOrOptions, y, width, height, threshold) = args + var imageRef: ImageWrapper? = null try { + val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColor must be a ImageWrapper" } + imageRef = image initOpenCvIfNeeded() val opt = when { - argList.size < 3 -> newNativeObject() - argList.size == 3 -> when { + args.size < 3 -> newNativeObject() + args.size == 3 -> when { xOrOptions.isJsNullish() -> newNativeObject() else -> xOrOptions as? NativeObject } else -> null } - scriptRuntime.images.colorFinder.findPointByColor( + return scriptRuntime.images.colorFinder.findPointByColor( image, Colors.toIntRhino(color), - opt?.let { parseThreshold(it).roundToInt() } ?: coerceIntNumber(threshold, DEFAULT_COLOR_THRESHOLD), + overriddenThreshold ?: opt?.let { parseThreshold(it).roundToInt() } ?: coerceIntNumber(threshold, DEFAULT_COLOR_THRESHOLD), buildRegionInternal(image, opt?.prop("region")?.takeUnless { it.isJsNullish() } ?: listOf(/* x = */ xOrOptions, y, width, height)) ).also { image.shoot() } } finally { - image.shoot() + ApiImages.shoot(imageRef) } } @Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findColor(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { - val (o, color, options) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColor must be a ImageWrapper" } - findPointByColor(scriptRuntime, arrayOf(image, color, options)) + fun findColor(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { argList -> + @Suppress("DEPRECATION") + findPointByColorRhino(scriptRuntime, argList, ::findColor.name) } @Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findColorInRegion(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { - val (o) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColorInRegion must be a ImageWrapper" } - findPointByColor(scriptRuntime, it) + fun findColorInRegion(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> + @Suppress("DEPRECATION") + findPointByColorRhino(scriptRuntime, argList, ::findColorInRegion.name) } @JvmStatic @RhinoRuntimeFunctionInterface - fun findPointByColorExactly(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { - val (o) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColorExactly must be a ImageWrapper" } - findPointByColor(scriptRuntime, it + /* threshold = */ 0) + fun findPointByColorExactly(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { argList -> + findPointByColorExactlyRhino(scriptRuntime, argList, ::findPointByColorExactly.name) + } + + @JvmStatic + fun findPointByColorExactlyRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): OpencvPoint? { + return findPointByColorRhino(scriptRuntime, args, funcName, 0) } @Deprecated("Deprecated in Java", ReplaceWith("findPointByColorExactly(image, color, x, y, width, height)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findColorEquals(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { - val (o) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColorEquals must be a ImageWrapper" } - findPointByColorExactly(scriptRuntime, it) + fun findColorEquals(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { argList -> + @Suppress("DEPRECATION") + findPointByColorExactlyRhino(scriptRuntime, argList, ::findColorEquals.name) } @JvmStatic @RhinoRuntimeFunctionInterface - fun findPointsByColor(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { - val (o, color, options) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointsByColor must be a ImageWrapper" } + fun findPointsByColor(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { argList -> + findPointsByColorRhino(scriptRuntime, argList, ::findPointsByColor.name) + } + + @JvmStatic + fun findPointsByColorRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): NativeArray { + val (o, color, options) = args + var imageRef: ImageWrapper? = null try { + val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointsByColor must be a ImageWrapper" } + imageRef = image initOpenCvIfNeeded() val opt = options as? NativeObject ?: newNativeObject() - scriptRuntime.images.colorFinder.findPointsByColor( + return scriptRuntime.images.colorFinder.findPointsByColor( image, Colors.toIntRhino(color), parseThreshold(opt).roundToInt(), opt.inquire("region") { region -> buildRegionInternal(image, region) }, ).toNativeArray() } finally { - image.shoot() + ApiImages.shoot(imageRef) } } @Deprecated("Deprecated in Java", ReplaceWith("findPointsByColor(image, color, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findAllPointsForColor(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { - val (o) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findAllPointsForColor must be a ImageWrapper" } - findPointsByColor(scriptRuntime, it) + fun findAllPointsForColor(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { argList -> + @Suppress("DEPRECATION") + findPointsByColorRhino(scriptRuntime, argList, ::findAllPointsForColor.name) } @JvmStatic @RhinoRuntimeFunctionInterface - fun findPointByColors(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { - val (o, firstColor, paths, options) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColors must be a ImageWrapper" } + fun findPointByColors(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { argList -> + findPointByColorsRhino(scriptRuntime, argList, ::findPointByColors.name) + } + + @JvmStatic + fun findPointByColorsRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): OpencvPoint? { + val (o, firstColor, paths, options) = args + var imageRef: ImageWrapper? = null try { + val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColors must be a ImageWrapper" } + imageRef = image require(paths is NativeArray) { "Argument \"paths\" ${paths.jsBrief()} for images.findPointByColors must be a JavaScript Array" } initOpenCvIfNeeded() val opt = options as? NativeObject ?: newNativeObject() - scriptRuntime.images.colorFinder.findPointByColors( + return scriptRuntime.images.colorFinder.findPointByColors( image, Colors.toIntRhino(firstColor), parseThreshold(opt).roundToInt(), @@ -968,22 +983,16 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt }.toIntArray(), ) } finally { - image.shoot() + ApiImages.shoot(imageRef) } } @Deprecated("Deprecated in Java", ReplaceWith("findPointByColors(image, firstColor, paths, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findMultiColors(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { - val (o, _, paths) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findMultiColors must be a ImageWrapper" } - require(paths is NativeArray) { - image.shoot() - "Argument \"paths\" ${paths.jsBrief()} for images.findMultiColors must be a JavaScript Array" - } - findPointByColors(scriptRuntime, it) + fun findMultiColors(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { argList -> + @Suppress("DEPRECATION") + findPointByColorsRhino(scriptRuntime, argList, ::findMultiColors.name) } @JvmStatic @@ -1014,26 +1023,33 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt @JvmStatic @RhinoRuntimeFunctionInterface fun findPointByImage(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> - val (o, template, xOrOptions, y, width, height, thresholdArg) = argList - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByImage must be a ImageWrapper" } - require(template is ImageWrapper) { - image.shoot() - "Argument \"template\" ${template.jsBrief()} for images.findPointByImage must be a ImageWrapper" - } + findPointByImageRhino(scriptRuntime, argList, ::findPointByImage.name) + } + + @JvmStatic + fun findPointByImageRhino(scriptRuntime: ScriptRuntime, args: Array, funcName: String): OpencvPoint? { + val (oA, oB, xOrOptions, y, width, height, thresholdArg) = args + var imageA: ImageWrapper? = null + var imageB: ImageWrapper? = null try { + val image = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.$funcName must be a ImageWrapper" } + imageA = image + val template = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB + require(template is ImageWrapper) { "Argument \"template\" ${oB.jsBrief()} for images.$funcName must be a ImageWrapper" } + imageB = template initOpenCvIfNeeded() - when { - argList.size > 2 && xOrOptions !is NativeObject -> { + return when { + args.size > 2 && xOrOptions !is NativeObject -> { val options = mapOf( "region" to listOf(/* x = */ xOrOptions, y, width, height), "threshold" to thresholdArg, ).toNativeObject() - findPointByImage(scriptRuntime, arrayOf(image, template, options)) + findPointByImageRhino(scriptRuntime, arrayOf(image, template, options), funcName) } else -> { val opt = when { - argList.size > 2 -> xOrOptions as? NativeObject + args.size > 2 -> xOrOptions as? NativeObject else -> null } ?: newNativeObject() val weakThreshold = parseWeakThreshold(opt, 0.6).toFloat() @@ -1044,49 +1060,39 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt } } } finally { - ApiImages.shoot(image, template) + ApiImages.shoot(imageA, imageB) } } @Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, options)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findImage(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { - val (o, template) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findImage must be a ImageWrapper" } - require(template is ImageWrapper) { - image.shoot() - "Argument \"template\" ${template.jsBrief()} for images.findImage must be a ImageWrapper" - } - findPointByImage(scriptRuntime, it) + fun findImage(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> + @Suppress("DEPRECATION") + findPointByImageRhino(scriptRuntime, argList, ::findImage.name) } @Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, x, y, width, height, threshold)")) @JvmStatic @RhinoRuntimeFunctionInterface - fun findImageInRegion(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { - val (o, template) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findImageInRegion must be a ImageWrapper" } - require(template is ImageWrapper) { - image.shoot() - "Argument \"template\" ${template.jsBrief()} for images.findImageInRegion must be a ImageWrapper" - } - findPointByImage(scriptRuntime, it) + fun findImageInRegion(scriptRuntime: ScriptRuntime, args: Array): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> + @Suppress("DEPRECATION") + findPointByImageRhino(scriptRuntime, argList, ::findImageInRegion.name) } @JvmStatic @RhinoRuntimeFunctionInterface fun matchTemplate(scriptRuntime: ScriptRuntime, args: Array): MatchingResult = ensureArgumentsLengthInRange(args, 2..3) { - val (o, template, options) = it - val image = if (o.isJsString()) read(scriptRuntime, arrayOf(coerceString(o), true))?.oneShot() else o - require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.matchTemplate must be a ImageWrapper" } - require(template is ImageWrapper) { - image.shoot() - "Argument \"template\" ${template.jsBrief()} for images.matchTemplate must be a ImageWrapper" - } + val (oA, oB, options) = it + var imageA: ImageWrapper? = null + var imageB: ImageWrapper? = null try { + val image = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA + require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.matchTemplate must be a ImageWrapper" } + imageA = image + val template = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB + require(template is ImageWrapper) { "Argument \"template\" ${template.jsBrief()} for images.matchTemplate must be a ImageWrapper" } + imageB = template initOpenCvIfNeeded() val opt = options as? NativeObject ?: newNativeObject() val weakThreshold = parseWeakThreshold(opt, 0.6).toFloat() @@ -1101,7 +1107,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt } MatchingResult(scriptRuntime.images.matchTemplate(image, template, weakThreshold, threshold, region, level, max, useTransparentMask)) } finally { - ApiImages.shoot(image, template) + ApiImages.shoot(imageA, imageB) } } @@ -1452,17 +1458,18 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt @RhinoRuntimeFunctionInterface fun isEqual(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsLength(args, 2) { argList -> val (oA, oB) = argList - val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA - require(imageA is ImageWrapper) { "Argument \"imageA\" ${imageA.jsBrief()} for images.isEqual must be a ImageWrapper}" } - val imageB = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB - require(imageB is ImageWrapper) { - imageA.shoot() - "Argument \"imageB\" ${imageB.jsBrief()} for images.isEqual must be a ImageWrapper" - } + var imageARef: ImageWrapper? = null + var imageBRef: ImageWrapper? = null try { + val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf(coerceString(oA), true))?.oneShot() else oA + require(imageA is ImageWrapper) { "Argument \"imageA\" ${imageA.jsBrief()} for images.isEqual must be a ImageWrapper}" } + imageARef = imageA + val imageB = if (oB.isJsString()) read(scriptRuntime, arrayOf(coerceString(oB), true))?.oneShot() else oB + require(imageB is ImageWrapper) { "Argument \"imageB\" ${imageB.jsBrief()} for images.isEqual must be a ImageWrapper" } + imageBRef = imageB ImageSimilarity.isEqual(imageA.mat, imageB.mat) } finally { - ApiImages.shoot(imageA, imageB) + ApiImages.shoot(imageARef, imageBRef) } } diff --git a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.kt b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.kt index f9c7d97f..c2538f3e 100644 --- a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.kt +++ b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.kt @@ -37,7 +37,7 @@ class CrashHandler(private val errorReportClass: Class<*>) : CrashHandleCallback if (crashTooManyTimes()) { return super.onCrashHandleStart(crashType, errorType, errorMessage, errorStack) } - startErrorReportActivity("$errorType: $errorMessage", errorStack ?: "[ No stack message ]") + startCrashReportActivity("$errorType: $errorMessage", errorStack ?: "[ No stack message ]") } catch (e: Throwable) { e.printStackTrace() } @@ -79,7 +79,7 @@ class CrashHandler(private val errorReportClass: Class<*>) : CrashHandleCallback mBuglyHandler = buglyHandler } - private fun startErrorReportActivity(msg: String, detail: String) { + private fun startCrashReportActivity(msg: String, detail: String) { Intent(GlobalAppContext.get(), errorReportClass).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) putExtra("message", msg) diff --git a/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.kt b/app/src/main/java/org/autojs/autojs/ui/error/CrashReportActivity.kt similarity index 93% rename from app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.kt rename to app/src/main/java/org/autojs/autojs/ui/error/CrashReportActivity.kt index e9ec7080..e3c3f893 100644 --- a/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/error/CrashReportActivity.kt @@ -16,9 +16,9 @@ import org.autojs.autojs6.databinding.ActivityErrorReportBinding * Created by Stardust on Feb 2, 2017. * Transformed by SuperMonster003 on Mar 10, 2025. */ -class ErrorReportActivity : BaseActivity() { +class CrashReportActivity : BaseActivity() { - private lateinit var errorMessage: String + private lateinit var crashMessage: String @SuppressLint("ClickableViewAccessibility") override fun onCreate(savedInstanceState: Bundle?) { @@ -29,7 +29,7 @@ class ErrorReportActivity : BaseActivity() { appendLine(briefOfCurrentVersionInt(true)) intent.getStringExtra("message")?.let { appendLine().appendLine(it.trimEnd()) } intent.getStringExtra("error")?.let { appendLine().appendLine(it.trimEnd()) } - }.also { errorMessage = it } + }.also { crashMessage = it } val binding = ActivityErrorReportBinding.inflate(layoutInflater).also { setContentView(it.root) @@ -62,7 +62,7 @@ class ErrorReportActivity : BaseActivity() { @SuppressLint("MissingSuperCall") override fun onBackPressed() = exit() - private fun copy() = ClipboardUtils.setClip(this, errorMessage) + private fun copy() = ClipboardUtils.setClip(this, crashMessage) private fun exit() = finishAffinity() diff --git a/version.properties b/version.properties index a48d3bda..40710897 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Sat Jun 28 19:48:58 CST 2025 -BUILD_TIME=1751111338507 +#Tue Jul 01 00:19:56 CST 2025 +BUILD_TIME=1751300396808 COMPILE_SDK_VERSION=35 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -19,6 +19,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=35 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3308 +VERSION_BUILD=3312 VERSION_NAME=6.7.0 Alpha2 VSCODE_EXT_REQUIRED_VERSION=1.0.8