6.7.0 - Alpha2 - 修复 images 部分相关方法可能引发内存泄露的问题 (issue #372)

This commit is contained in:
SuperMonster003
2025-07-01 00:51:31 +08:00
parent 23f84d935d
commit c1973beeb0
19 changed files with 229 additions and 509 deletions

View File

@@ -11,17 +11,18 @@
"使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题", "使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题",
"调用 images.requestScreenCapture 时用户取消授权可能导致应用崩溃的问题", "调用 images.requestScreenCapture 时用户取消授权可能导致应用崩溃的问题",
"images 部分相关方法出现异常时 oneShot 标记功能失效的问题 _[`issue #372`](http://issues.autojs6.com/372)_", "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)_", "Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_",
"打包应用无法正常使用 Paddle OCR 与 Rapid OCR 功能的问题", "打包应用无法正常使用 Paddle OCR 与 Rapid OCR 功能的问题",
"版本历史页面部分系统因字体差别导致统计数据显示不完整的问题", "版本历史页面部分系统因字体差别导致统计数据显示不完整的问题",
"ErrorDialogActivity 可能无法正常启动的问题 _[`issue #414`](http://issues.autojs6.com/414)_ _[`issue #340`](http://issues.autojs6.com/340#issuecomment-2973485826)_", "ErrorDialogActivity 可能无法正常启动的问题 _[`issue #414`](http://issues.autojs6.com/414)_ _[`issue #340`](http://issues.autojs6.com/340#issuecomment-2973485826)_",
"错误报告页面复制详细信息功能失效的问题" "崩溃报告页面复制详细信息功能失效的问题"
], ],
"improvement": [ "improvement": [
"http 模块相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_", "http 模块相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_",
"android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数", "android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数",
"内置模块相关方法实参类型的异常消息增加类型摘要信息", "内置模块相关方法实参类型的异常消息增加类型摘要信息",
"错误报告页面支持双指缩放调整字体大小并添加常用功能按钮" "崩溃报告页面支持双指缩放调整字体大小并添加常用功能按钮"
], ],
"dependency": [ "dependency": [
"附加 Androidx Core (KTX) 版本 1.16.0", "附加 Androidx Core (KTX) 版本 1.16.0",

View File

@@ -290,8 +290,8 @@
android:name="org.autojs.autojs.ui.settings.DeveloperOptionsActivity" android:name="org.autojs.autojs.ui.settings.DeveloperOptionsActivity"
android:theme="@style/AppTheme.Settings" /> android:theme="@style/AppTheme.Settings" />
<!-- <activity android:name="org.autojs.autojs.ui.error.ErrorReportActivity" android:process=":crash_report"/> --> <!-- <activity android:name="org.autojs.autojs.ui.error.CrashReportActivity" android:process=":crash_report"/> -->
<activity android:name="org.autojs.autojs.ui.error.ErrorReportActivity" /> <activity android:name="org.autojs.autojs.ui.error.CrashReportActivity" />
<activity <activity
android:name="org.autojs.autojs.external.tasker.TaskerScriptEditActivity" android:name="org.autojs.autojs.external.tasker.TaskerScriptEditActivity"

View File

@@ -31,7 +31,7 @@ import org.autojs.autojs.pluginclient.DevPluginService
import org.autojs.autojs.timing.TimedTaskManager import org.autojs.autojs.timing.TimedTaskManager
import org.autojs.autojs.timing.TimedTaskScheduler import org.autojs.autojs.timing.TimedTaskScheduler
import org.autojs.autojs.tool.CrashHandler import org.autojs.autojs.tool.CrashHandler
import org.autojs.autojs.ui.error.ErrorReportActivity import org.autojs.autojs.ui.error.CrashReportActivity
import org.autojs.autojs.ui.floating.FloatyWindowManger import org.autojs.autojs.ui.floating.FloatyWindowManger
import org.autojs.autojs.util.ViewUtils import org.autojs.autojs.util.ViewUtils
import org.autojs.autojs6.BuildConfig import org.autojs.autojs6.BuildConfig
@@ -89,7 +89,7 @@ class App : MultiDexApplication() {
private fun setUpDebugEnvironment() { private fun setUpDebugEnvironment() {
Bugly.isDev = false Bugly.isDev = false
val crashHandler = CrashHandler(ErrorReportActivity::class.java) val crashHandler = CrashHandler(CrashReportActivity::class.java)
val strategy = CrashReport.UserStrategy(applicationContext) val strategy = CrashReport.UserStrategy(applicationContext)
strategy.setCrashHandleCallback(crashHandler) strategy.setCrashHandleCallback(crashHandler)

View File

@@ -1,61 +0,0 @@
package org.autojs.autojs.core.cleaner;
import android.util.Log;
import org.autojs.autojs.core.ref.MonitorResource;
import org.autojs.autojs.core.ref.NativeObjectReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by SuperMonster003 on Dec 22, 2023.
*/
// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 22, 2023.
public final class Cleaner {
public static final Cleaner instance = new Cleaner();
public static final AtomicInteger pointer = new AtomicInteger();
public static final ReferenceQueue<Object> 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<MonitorResource> resourceNativeCleaner = new NativeObjectReference<>(resource, referenceQueue, cleaner);
resourceNativeCleaner.pointer = resource.getPointer();
resource.setNativeObjectReference(resourceNativeCleaner);
RegisteredCleaners.registeredCleaners.add(resourceNativeCleaner);
pointer.incrementAndGet();
}
}

View File

@@ -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);
}

View File

@@ -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<NativeObjectReference<MonitorResource>> registeredCleaners = Collections.newSetFromMap(new ConcurrentHashMap<>());
}

View File

@@ -9,8 +9,6 @@ import androidx.core.graphics.get
import org.autojs.autojs.annotation.ScriptInterface import org.autojs.autojs.annotation.ScriptInterface
import org.autojs.autojs.core.opencv.Mat import org.autojs.autojs.core.opencv.Mat
import org.autojs.autojs.core.opencv.OpenCVHelper 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.pio.UncheckedIOException
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.Images import org.autojs.autojs.runtime.api.Images
@@ -24,7 +22,6 @@ import org.opencv.imgproc.Imgproc
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.FileOutputStream import java.io.FileOutputStream
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicLong
/** /**
* Created by Stardust on Nov 25, 2017. * Created by Stardust on Nov 25, 2017.
@@ -32,14 +29,14 @@ import java.util.concurrent.atomic.AtomicLong
* Transformed by SuperMonster003 on May 16, 2023. * Transformed by SuperMonster003 on May 16, 2023.
*/ */
// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 20, 2023. // @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 20, 2023.
open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource { open class ImageWrapper : Shootable<ImageWrapper> {
private var mScriptRuntime: ScriptRuntime private var mScriptRuntime: ScriptRuntime
private var mMat: Mat? = null private var mMat: Mat? = null
private var mBgrMat: Mat? = null private var mBgrMat: Mat? = null
private var mBitmap: Bitmap? = null private var mBitmap: Bitmap? = null
private var mRef: NativeObjectReference<MonitorResource>? = null private var mMediaImage: Image? = null
private var mPlane: Image.Plane? = null private var mPlane: Image.Plane? = null
private var mWidth = 0 private var mWidth = 0
@@ -47,12 +44,6 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
private var mIsRecycled = false private var mIsRecycled = false
private var mIsOneShot = false private var mIsOneShot = false
private var mId = 0L
private val mNextId = AtomicLong()
var mediaImage: Image? = null
private set
val width val width
get() = mWidth.also { ensureNotRecycled() } get() = mWidth.also { ensureNotRecycled() }
@@ -71,10 +62,7 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
val bitmap = createBitmap(mat.width(), mat.height()).also { mBitmap = it } val bitmap = createBitmap(mat.width(), mat.height()).also { mBitmap = it }
Utils.matToBitmap(mat, bitmap) Utils.matToBitmap(mat, bitmap)
} else { } else {
val mediaImage = mediaImage mMediaImage?.let { mBitmap = toBitmap(it) }
if (mediaImage != null) {
mBitmap = toBitmap(mediaImage)
}
} }
} }
return mBitmap ?: throw Exception("Bitmap of ImageWrapper should never be null") return mBitmap ?: throw Exception("Bitmap of ImageWrapper should never be null")
@@ -93,7 +81,7 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
Utils.bitmapToMat(bitmap, newMat) Utils.bitmapToMat(bitmap, newMat)
return newMat return newMat
} }
if (mediaImage != null) { if (mMediaImage != null) {
val plane = plane ?: throw AssertionError("Image plain is null") val plane = plane ?: throw AssertionError("Image plain is null")
plane.buffer.position(0) plane.buffer.position(0)
return Mat(mHeight, mWidth, CvType.CV_8UC4, plane.buffer, plane.rowStride.toLong()).also { mMat = it } return Mat(mHeight, mWidth, CvType.CV_8UC4, plane.buffer, plane.rowStride.toLong()).also { mMat = it }
@@ -111,13 +99,12 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
private set(plane) { private set(plane) {
mPlane = 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, width: Int, height: Int) : this(scriptRuntime, createBitmap(width, height))
constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap) { constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap) {
mScriptRuntime = scriptRuntime mScriptRuntime = scriptRuntime
mId = mNextId.incrementAndGet()
mBitmap = bitmap.also { addToList(it) } mBitmap = bitmap.also { addToList(it) }
mWidth = bitmap.width mWidth = bitmap.width
mHeight = bitmap.height mHeight = bitmap.height
@@ -125,7 +112,6 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
constructor(scriptRuntime: ScriptRuntime, mat: Mat) { constructor(scriptRuntime: ScriptRuntime, mat: Mat) {
mScriptRuntime = scriptRuntime mScriptRuntime = scriptRuntime
mId = mNextId.incrementAndGet()
mMat = mat.also { addToList(it) } mMat = mat.also { addToList(it) }
mWidth = mat.cols() mWidth = mat.cols()
mHeight = mat.rows() mHeight = mat.rows()
@@ -133,7 +119,6 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
constructor(scriptRuntime: ScriptRuntime, mat: org.opencv.core.Mat) { constructor(scriptRuntime: ScriptRuntime, mat: org.opencv.core.Mat) {
mScriptRuntime = scriptRuntime mScriptRuntime = scriptRuntime
mId = mNextId.incrementAndGet()
mMat = when (mat.nativeObj != 0L) { mMat = when (mat.nativeObj != 0L) {
true -> Mat(mat.nativeObj) true -> Mat(mat.nativeObj)
else -> Mat(mat.rows(), mat.cols(), mat.type()) else -> Mat(mat.rows(), mat.cols(), mat.type())
@@ -144,7 +129,6 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap, mat: Mat?) { constructor(scriptRuntime: ScriptRuntime, bitmap: Bitmap, mat: Mat?) {
mScriptRuntime = scriptRuntime mScriptRuntime = scriptRuntime
mId = mNextId.incrementAndGet()
mMat = mat?.also { addToList(it) } mMat = mat?.also { addToList(it) }
mBitmap = bitmap.also { addToList(it) } mBitmap = bitmap.also { addToList(it) }
mWidth = bitmap.width mWidth = bitmap.width
@@ -153,8 +137,7 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
constructor(scriptRuntime: ScriptRuntime, mediaImage: Image) { constructor(scriptRuntime: ScriptRuntime, mediaImage: Image) {
mScriptRuntime = scriptRuntime mScriptRuntime = scriptRuntime
mId = mNextId.incrementAndGet() mMediaImage = mediaImage.also { addToList(it) }
this.mediaImage = mediaImage.also { addToList(it) }
mWidth = mediaImage.width mWidth = mediaImage.width
mHeight = mediaImage.height mHeight = mediaImage.height
} }
@@ -269,12 +252,10 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
OpenCVHelper.release(it) OpenCVHelper.release(it)
mBgrMat = null mBgrMat = null
} }
mediaImage?.let { mMediaImage?.let {
it.close() it.close()
mediaImage = null mMediaImage = null
} mPlane = null
mRef?.let {
it.pointer = 0L
} }
mIsRecycled = true mIsRecycled = true
} }
@@ -301,12 +282,6 @@ open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
} }
} }
override fun getPointer() = mId
override fun setNativeObjectReference(reference: NativeObjectReference<MonitorResource>) {
mRef = reference
}
companion object { companion object {
private val imageList = ArrayList<WeakReference<Any>>() private val imageList = ArrayList<WeakReference<Any>>()

View File

@@ -158,32 +158,28 @@ public class TemplateMatching {
Mat currentTemplate = getPyramidDownAtLevel(template, level); Mat currentTemplate = getPyramidDownAtLevel(template, level);
Mat transparentMask = useTransparentMask ? createTransparentMask(currentTemplate) : null; Mat transparentMask = useTransparentMask ? createTransparentMask(currentTemplate) : null;
boolean shouldStop; // 如果在上一轮中没有匹配到图片, 则考虑是否退出匹配
if (previousMatchResult.isEmpty()) {
Label_Check_Should_Stop: // 如果不是第一次匹配, 并且不满足shouldContinueMatching的条件, 则直接退出匹配
{ if (!isFirstMatching && !shouldContinueMatching(level, selectPyramidLevel)) {
// 如果在上一轮中没有匹配到图片, 则考虑是否退出匹配 releaseIfNeeded(src, img);
if (previousMatchResult.isEmpty()) { releaseIfNeeded(currentTemplate, template);
// 如果不是第一次匹配, 并且不满足shouldContinueMatching的条件, 则直接退出匹配 OpenCVHelper.release(transparentMask);
if (!isFirstMatching && !shouldContinueMatching(level, selectPyramidLevel)) { break;
shouldStop = true; }
break Label_Check_Should_Stop; Mat matchResult = matchTemplate(src, currentTemplate, matchingMethod, transparentMask);
} getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, null, finalMatchResult);
Mat matchResult = matchTemplate(src, currentTemplate, matchingMethod, transparentMask); OpenCVHelper.release(matchResult);
getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, null, finalMatchResult); } else {
OpenCVHelper.release(matchResult); for (Match match : previousMatchResult) {
} else { // 根据上一轮的匹配点, 计算本次匹配的区域
for (Match match : previousMatchResult) { Rect roi = getROI(match.point, src, currentTemplate);
// 根据上一轮的匹配点, 计算本次匹配的区域 Mat m = new Mat(src, roi);
Rect roi = getROI(match.point, src, currentTemplate); Mat matchResult = matchTemplate(m, currentTemplate, matchingMethod, transparentMask);
Mat m = new Mat(src, roi); getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, roi, finalMatchResult);
Mat matchResult = matchTemplate(m, currentTemplate, matchingMethod, transparentMask); OpenCVHelper.release(m);
getBestMatched(matchResult, currentTemplate, matchingMethod, weakThreshold, currentMatchResult, limit, level, roi, finalMatchResult); OpenCVHelper.release(matchResult);
OpenCVHelper.release(m);
OpenCVHelper.release(matchResult);
}
} }
shouldStop = false;
} }
releaseIfNeeded(src, img); releaseIfNeeded(src, img);
releaseIfNeeded(currentTemplate, template); releaseIfNeeded(currentTemplate, template);
@@ -191,26 +187,24 @@ public class TemplateMatching {
logger.addSplit("level:" + level + ", result:" + previousMatchResult); logger.addSplit("level:" + level + ", result:" + previousMatchResult);
if (!shouldStop) { // 把满足强阈值的点找出来, 加到最终结果列表
// 把满足强阈值的点找出来, 加到最终结果列表 if (!currentMatchResult.isEmpty()) {
if (!currentMatchResult.isEmpty()) { Iterator<Match> iterator = currentMatchResult.iterator();
Iterator<Match> iterator = currentMatchResult.iterator(); while (iterator.hasNext()) {
while (iterator.hasNext()) { Match match = iterator.next();
Match match = iterator.next(); if (match.similarity >= strictThreshold) {
if (match.similarity >= strictThreshold) { pyrUp(match.point, level);
pyrUp(match.point, level); finalMatchResult.add(match);
finalMatchResult.add(match); iterator.remove();
iterator.remove();
}
}
// 如果所有结果都满足强阈值, 则退出循环, 返回最终结果
if (currentMatchResult.isEmpty()) {
break;
} }
} }
previousMatchResult = currentMatchResult; // 如果所有结果都满足强阈值, 则退出循环, 返回最终结果
isFirstMatching = false; if (currentMatchResult.isEmpty()) {
break;
}
} }
isFirstMatching = false;
previousMatchResult = currentMatchResult;
} }
logger.addSplit("result:" + finalMatchResult); logger.addSplit("result:" + finalMatchResult);
logger.dumpToLog(); logger.dumpToLog();

View File

@@ -1,10 +1,6 @@
package org.autojs.autojs.core.opencv; package org.autojs.autojs.core.opencv;
import androidx.annotation.NonNull; 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.CvType;
import org.opencv.core.Range; import org.opencv.core.Range;
import org.opencv.core.Rect; import org.opencv.core.Rect;
@@ -15,105 +11,80 @@ import org.opencv.imgproc.Imgproc;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class Mat extends org.opencv.core.Mat implements MonitorResource { public class Mat extends org.opencv.core.Mat {
public static final ICleaner MAT_CLEANER = new MatCleaner(null);
private volatile boolean mReleased; private volatile boolean mReleased;
private static final Method nClone = findMethod("n_clone", Long.TYPE); 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 nOnes = findMethod("n_ones", Integer.TYPE, Integer.TYPE, Integer.TYPE);
private static final Method nRelease = findMethod("n_release", Long.TYPE); private static final Method nRelease = findMethod("n_release", Long.TYPE);
private NativeObjectReference<MonitorResource> mReference;
public Mat() { public Mat() {
super(); super();
init();
} }
public Mat(long addr) { public Mat(long addr) {
super(addr); super(addr);
init();
} }
public Mat(int rows, int cols, int type) { public Mat(int rows, int cols, int type) {
super(rows, cols, type); super(rows, cols, type);
init();
} }
public Mat(Size size, int type) { public Mat(Size size, int type) {
super(size, type); super(size, type);
init();
} }
public Mat(int rows, int cols, int type, Scalar s) { public Mat(int rows, int cols, int type, Scalar s) {
super(rows, cols, type, s); super(rows, cols, type, s);
init();
} }
public Mat(Size size, int type, Scalar s) { public Mat(Size size, int type, Scalar s) {
super(size, type, s); super(size, type, s);
init();
} }
public Mat(Mat m, Range rowRange, Range colRange) { public Mat(Mat m, Range rowRange, Range colRange) {
super(m, rowRange, colRange); super(m, rowRange, colRange);
init();
} }
public Mat(Mat m, Range rowRange) { public Mat(Mat m, Range rowRange) {
super(m, rowRange); super(m, rowRange);
init();
} }
public Mat(Mat m, Rect roi) { public Mat(Mat m, Rect roi) {
super(m, roi); super(m, roi);
init();
} }
public Mat(int rows, int cols, int type, ByteBuffer data) { public Mat(int rows, int cols, int type, ByteBuffer data) {
super(rows, cols, type, data); super(rows, cols, type, data);
init();
} }
public Mat(int rows, int cols, int type, ByteBuffer data, long step) { public Mat(int rows, int cols, int type, ByteBuffer data, long step) {
super(rows, cols, type, data, step); super(rows, cols, type, data, step);
init();
} }
public Mat(org.opencv.core.Mat opencvMat, Range rowRange) { public Mat(org.opencv.core.Mat opencvMat, Range rowRange) {
super(opencvMat, rowRange); super(opencvMat, rowRange);
init();
} }
public Mat(org.opencv.core.Mat opencvMat, Range rowRange, Range colRange) { public Mat(org.opencv.core.Mat opencvMat, Range rowRange, Range colRange) {
super(opencvMat, rowRange, colRange); super(opencvMat, rowRange, colRange);
init();
} }
public Mat(org.opencv.core.Mat opencvMat, Rect rect) { public Mat(org.opencv.core.Mat opencvMat, Rect rect) {
super(opencvMat, rect); super(opencvMat, rect);
init();
} }
public Mat(org.opencv.core.Mat opencvMat, Range[] ranges) { public Mat(org.opencv.core.Mat opencvMat, Range[] ranges) {
super(opencvMat, ranges); super(opencvMat, ranges);
init();
} }
public Mat(int[] sizes, int type) { public Mat(int[] sizes, int type) {
super(sizes, type); super(sizes, type);
init();
} }
public Mat(int[] sizes, int type, Scalar scalar) { public Mat(int[] sizes, int type, Scalar scalar) {
super(sizes, type, 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) { 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; return nRelease;
} }
@Override
public long getPointer() {
return super.nativeObj;
}
@Override
public void setNativeObjectReference(final NativeObjectReference<MonitorResource> reference) {
mReference = reference;
}
public String getPointerString() {
return Long.toString(super.nativeObj);
}
public boolean isReleased() { public boolean isReleased() {
return mReleased || mReference != null && mReference.pointer == 0L; return mReleased;
} }
@Override @Override
public void release() { public void release() {
if (mReleased) return; if (!mReleased) {
synchronized (this) { synchronized (this) {
if (mReleased) return; if (!mReleased) {
mReleased = true; super.release();
if (mReference != null) { mReleased = true;
mReference.pointer = 0L; }
} }
super.release();
} }
} }

View File

@@ -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);
}
}
}

View File

@@ -1,62 +1,41 @@
package org.autojs.autojs.core.opencv; 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; import org.opencv.core.Point;
/** /**
* Modified by SuperMonster003 as of Jan 21, 2023. * Modified by SuperMonster003 as of Jan 21, 2023.
*/ */
// @Reference to Auto.js Pro 9.3.11 by SuperMonster003 on Dec 18, 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 volatile boolean mReleased = false;
private NativeObjectReference<MonitorResource> mReference;
public MatOfPoint() { public MatOfPoint() {
init(); super();
} }
public MatOfPoint(long l) { public MatOfPoint(long l) {
super(l); super(l);
init();
} }
public MatOfPoint(org.opencv.core.Mat mat) { public MatOfPoint(org.opencv.core.Mat mat) {
super(mat); super(mat);
init();
} }
public MatOfPoint(Point... pointArray) { public MatOfPoint(Point... pointArray) {
super(pointArray); super(pointArray);
init();
}
private void init() {
Cleaner.instance.cleanup(this, Mat.MAT_CLEANER);
} }
@Override @Override
public void release() { public void release() {
if (mReleased) return; if (!mReleased) {
synchronized (this) { synchronized (this) {
if (mReleased) return; if (!mReleased) {
mReleased = true; super.release();
if (mReference != null) { mReleased = true;
mReference.pointer = 0L; }
} }
super.release();
} }
} }
public long getPointer() {
return nativeObj;
}
public void setNativeObjectReference(NativeObjectReference<MonitorResource> reference) {
mReference = reference;
}
} }

View File

@@ -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<MonitorResource> reference);
}

View File

@@ -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<T> extends PhantomReference<T> {
public final ICleaner cleaner;
public volatile long pointer;
public NativeObjectReference(final T referent, final ReferenceQueue<? super T> referenceQueue, final ICleaner cleaner) {
super(referent, referenceQueue);
this.cleaner = cleaner;
}
}

View File

@@ -4,10 +4,6 @@ import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.autojs.autojs.annotation.ScriptInterface; 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.autojs.autojs.util.ImageUtils;
import org.opencv.calib3d.Calib3d; import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core; import org.opencv.core.Core;
@@ -314,11 +310,10 @@ public final class ImageFeatureMatching {
* A reusable bundle of feature-extraction results for a single image. * A reusable bundle of feature-extraction results for a single image.
* zh-CN: 单张图片的特征提取结果集合. * zh-CN: 单张图片的特征提取结果集合.
*/ */
public static class FeatureMatchingDescriptor implements MonitorResource { public static class FeatureMatchingDescriptor {
private final Mat mDescriptors; private final Mat mDescriptors;
private long mNativePtr; private long mNativePtr;
private NativeObjectReference<MonitorResource> mRef;
private final MatOfKeyPoint mKeyPoint; private final MatOfKeyPoint mKeyPoint;
private final MatOfPoint2f mCorners; private final MatOfPoint2f mCorners;
@@ -344,18 +339,12 @@ public final class ImageFeatureMatching {
mNativePtr = descriptors.nativeObj; mNativePtr = descriptors.nativeObj;
mKeyPoint = keyPoint; mKeyPoint = keyPoint;
mCorners = corners; mCorners = corners;
Cleaner.instance.cleanup(this, SelfCleaner.INSTANCE);
} }
public long getNativePtr() { public long getNativePtr() {
return mNativePtr; return mNativePtr;
} }
@Override
public long getPointer() {
return mNativePtr;
}
public MatOfKeyPoint getKeyPoint() { public MatOfKeyPoint getKeyPoint() {
return mKeyPoint; return mKeyPoint;
} }
@@ -367,20 +356,12 @@ public final class ImageFeatureMatching {
public void release() { public void release() {
synchronized (this) { synchronized (this) {
if (mNativePtr != 0L) { if (mNativePtr != 0L) {
SelfCleaner.INSTANCE.cleanup(mNativePtr); releaseFeatureMatchingDescriptor(mNativePtr);
mNativePtr = 0L; mNativePtr = 0L;
if (mRef != null) {
mRef.pointer = 0L;
}
} }
} }
} }
@Override
public void setNativeObjectReference(NativeObjectReference<MonitorResource> ref) {
mRef = ref;
}
public void setNativePtr(long nativePtr) { public void setNativePtr(long nativePtr) {
mNativePtr = nativePtr; mNativePtr = nativePtr;
} }
@@ -389,23 +370,6 @@ public final class ImageFeatureMatching {
return mCorners; 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);
}
}
} }
/** /**

View File

@@ -628,7 +628,6 @@ public class Images {
throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.findImage", "template")); throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.findImage", "template"));
} }
Mat src = image.getMat(); Mat src = image.getMat();
boolean shouldReleaseMat = false;
if (rect != null) { if (rect != null) {
if (template.getWidth() > rect.width) { if (template.getWidth() > rect.width) {
throw new Exception(mContext.getString(R.string.error_excessive_width_for_template_n_region, 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)); throw new Exception(mContext.getString(R.string.error_excessive_height_for_template_n_region, template.getHeight(), rect.height));
} }
src = new Mat(src, rect); src = new Mat(src, rect);
shouldReleaseMat = true;
} }
@Nullable @Nullable
org.opencv.core.Point point; org.opencv.core.Point point;
@@ -645,10 +643,10 @@ public class Images {
point = TemplateMatching.singleTemplateMatching( point = TemplateMatching.singleTemplateMatching(
src, src,
template.getMat(), template.getMat(),
new TemplateMatching.Options(-1, weakThreshold, strictThreshold, maxLevel) new TemplateMatching.Options(TemplateMatching.MATCHING_METHOD_NONE, weakThreshold, strictThreshold, maxLevel)
); );
} finally { } finally {
if (shouldReleaseMat) { if (src != image.getMat()) {
OpenCVHelper.release(src); OpenCVHelper.release(src);
} }
} }

View File

@@ -760,14 +760,15 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun concat(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ImageWrapper = ensureArgumentsLengthInRange(args, 2..3) { fun concat(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ImageWrapper = ensureArgumentsLengthInRange(args, 2..3) {
val (oA, oB, direction) = it val (oA, oB, direction) = it
val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(oA), true))?.oneShot() else oA var imageA: ImageWrapper? = null
require(imageA is ImageWrapper) { "Argument \"imageA\" ${imageA.jsBrief()} for images.concat must be a ImageWrapper" } var imageB: ImageWrapper? = null
val imageB = if (oB.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(oB), true))?.oneShot() else oB
require(imageB is ImageWrapper) {
imageA.shoot()
"Argument \"imageB\" ${imageB.jsBrief()} for images.concat must be a ImageWrapper"
}
try { try {
val imageARaw = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(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<Any>(coerceString(oB), true))?.oneShot() else oB
require(imageBRaw is ImageWrapper) { "Argument \"imageB\" ${imageBRaw.jsBrief()} for images.concat must be a ImageWrapper" }
imageB = imageBRaw
initOpenCvIfNeeded() initOpenCvIfNeeded()
ApiImages.concat(scriptRuntime, imageA, imageB, directionToGravityToConcat(direction)) ApiImages.concat(scriptRuntime, imageA, imageB, directionToGravityToConcat(direction))
} finally { } finally {
@@ -777,48 +778,55 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun detectColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 4..6) { fun detectColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 4..6) { argList ->
val (o, color, x, y, threshold, algorithm) = it detectColorRhino(scriptRuntime, argList, ::detectColor.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o }
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectColor must be a ImageWrapper" }
@JvmStatic
fun detectColorRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): Boolean {
val (o, color, x, y, threshold, algorithm) = args
var imageRef: ImageWrapper? = null
try { try {
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectColor must be a ImageWrapper" }
imageRef = image
initOpenCvIfNeeded() initOpenCvIfNeeded()
val pixel = pixel(scriptRuntime, arrayOf(image, coerceIntNumber(x), coerceIntNumber(y))) 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)) .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()) .detectColor(Colors.redRhino(pixel).roundToInt(), Colors.greenRhino(pixel).roundToInt(), Colors.blueRhino(pixel).roundToInt())
} finally { } finally {
image.shoot() ApiImages.shoot(imageRef)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("detectColor(image, color, x, y, threshold, algorithm)")) @Deprecated("Deprecated in Java", ReplaceWith("detectColor(image, color, x, y, threshold, algorithm)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun detectsColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 4..6) { fun detectsColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 4..6) { argList ->
val (o) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o detectColorRhino(scriptRuntime, argList, ::detectsColor.name)
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectsColor must be a ImageWrapper" }
try {
initOpenCvIfNeeded()
detectColor(scriptRuntime, it)
} finally {
image.shoot()
}
} }
// @Reference to module __images__.js from Auto.js Pro 9.3.11 by SuperMonster003 on May 10, 2025. // @Reference to module __images__.js from Auto.js Pro 9.3.11 by SuperMonster003 on May 10, 2025.
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun detectMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 5..6) { fun detectMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 5..6) { argList ->
val (o, x, y, firstColor, paths, options) = it detectMultiColorsRhino(scriptRuntime, argList, ::detectMultiColors.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o }
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.detectMultiColors must be a ImageWrapper" }
@JvmStatic
fun detectMultiColorsRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): Boolean {
val (o, x, y, firstColor, paths, options) = args
var imageRef: ImageWrapper? = null
try { try {
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(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" } require(paths is NativeArray) { "Argument \"paths\" ${paths.jsBrief()} for images.detectMultiColors must be a JavaScript Array" }
initOpenCvIfNeeded() initOpenCvIfNeeded()
val opt = options as? NativeObject ?: newNativeObject() val opt = options as? NativeObject ?: newNativeObject()
scriptRuntime.images.colorFinder.detectMultiColors( return scriptRuntime.images.colorFinder.detectMultiColors(
image, image,
coerceIntNumber(x), coerceIntNumber(x),
coerceIntNumber(y), coerceIntNumber(y),
@@ -831,133 +839,140 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
}.toIntArray(), }.toIntArray(),
) )
} finally { } finally {
image.shoot() ApiImages.shoot(imageRef)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("detectMultiColors(image, x, y, firstColor, paths, options)")) @Deprecated("Deprecated in Java", ReplaceWith("detectMultiColors(image, x, y, firstColor, paths, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun detectsMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 5..6) { fun detectsMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLengthInRange(args, 5..6) { argList ->
val (o, _, _, _, paths) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o detectMultiColorsRhino(scriptRuntime, argList, ::detectsMultiColors.name)
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()
}
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findPointByColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> fun findPointByColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList ->
val (o, color, xOrOptions, y, width, height, threshold) = argList findPointByColorRhino(scriptRuntime, argList, ::findPointByColor.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o }
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColor must be a ImageWrapper" }
@JvmStatic
fun findPointByColorRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String, overriddenThreshold: Int? = null): OpencvPoint? {
val (o, color, xOrOptions, y, width, height, threshold) = args
var imageRef: ImageWrapper? = null
try { try {
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColor must be a ImageWrapper" }
imageRef = image
initOpenCvIfNeeded() initOpenCvIfNeeded()
val opt = when { val opt = when {
argList.size < 3 -> newNativeObject() args.size < 3 -> newNativeObject()
argList.size == 3 -> when { args.size == 3 -> when {
xOrOptions.isJsNullish() -> newNativeObject() xOrOptions.isJsNullish() -> newNativeObject()
else -> xOrOptions as? NativeObject else -> xOrOptions as? NativeObject
} }
else -> null else -> null
} }
scriptRuntime.images.colorFinder.findPointByColor( return scriptRuntime.images.colorFinder.findPointByColor(
image, image,
Colors.toIntRhino(color), 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)) buildRegionInternal(image, opt?.prop("region")?.takeUnless { it.isJsNullish() } ?: listOf(/* x = */ xOrOptions, y, width, height))
).also { image.shoot() } ).also { image.shoot() }
} finally { } finally {
image.shoot() ApiImages.shoot(imageRef)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { fun findColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { argList ->
val (o, color, options) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByColorRhino(scriptRuntime, argList, ::findColor.name)
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColor must be a ImageWrapper" }
findPointByColor(scriptRuntime, arrayOf(image, color, options))
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByColor(image, color, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findColorInRegion(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { fun findColorInRegion(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList ->
val (o) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByColorRhino(scriptRuntime, argList, ::findColorInRegion.name)
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColorInRegion must be a ImageWrapper" }
findPointByColor(scriptRuntime, it)
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findPointByColorExactly(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { fun findPointByColorExactly(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { argList ->
val (o) = it findPointByColorExactlyRhino(scriptRuntime, argList, ::findPointByColorExactly.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(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) @JvmStatic
fun findPointByColorExactlyRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): OpencvPoint? {
return findPointByColorRhino(scriptRuntime, args, funcName, 0)
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByColorExactly(image, color, x, y, width, height)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByColorExactly(image, color, x, y, width, height)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findColorEquals(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { fun findColorEquals(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..6) { argList ->
val (o) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByColorExactlyRhino(scriptRuntime, argList, ::findColorEquals.name)
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findColorEquals must be a ImageWrapper" }
findPointByColorExactly(scriptRuntime, it)
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findPointsByColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { fun findPointsByColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { argList ->
val (o, color, options) = it findPointsByColorRhino(scriptRuntime, argList, ::findPointsByColor.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o }
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointsByColor must be a ImageWrapper" }
@JvmStatic
fun findPointsByColorRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): NativeArray {
val (o, color, options) = args
var imageRef: ImageWrapper? = null
try { try {
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointsByColor must be a ImageWrapper" }
imageRef = image
initOpenCvIfNeeded() initOpenCvIfNeeded()
val opt = options as? NativeObject ?: newNativeObject() val opt = options as? NativeObject ?: newNativeObject()
scriptRuntime.images.colorFinder.findPointsByColor( return scriptRuntime.images.colorFinder.findPointsByColor(
image, image,
Colors.toIntRhino(color), Colors.toIntRhino(color),
parseThreshold(opt).roundToInt(), parseThreshold(opt).roundToInt(),
opt.inquire("region") { region -> buildRegionInternal(image, region) }, opt.inquire("region") { region -> buildRegionInternal(image, region) },
).toNativeArray() ).toNativeArray()
} finally { } finally {
image.shoot() ApiImages.shoot(imageRef)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointsByColor(image, color, options)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointsByColor(image, color, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findAllPointsForColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { fun findAllPointsForColor(scriptRuntime: ScriptRuntime, args: Array<out Any?>): NativeArray = ensureArgumentsLengthInRange(args, 2..3) { argList ->
val (o) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointsByColorRhino(scriptRuntime, argList, ::findAllPointsForColor.name)
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findAllPointsForColor must be a ImageWrapper" }
findPointsByColor(scriptRuntime, it)
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findPointByColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { fun findPointByColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { argList ->
val (o, firstColor, paths, options) = it findPointByColorsRhino(scriptRuntime, argList, ::findPointByColors.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o }
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.findPointByColors must be a ImageWrapper" }
@JvmStatic
fun findPointByColorsRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): OpencvPoint? {
val (o, firstColor, paths, options) = args
var imageRef: ImageWrapper? = null
try { try {
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(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" } require(paths is NativeArray) { "Argument \"paths\" ${paths.jsBrief()} for images.findPointByColors must be a JavaScript Array" }
initOpenCvIfNeeded() initOpenCvIfNeeded()
val opt = options as? NativeObject ?: newNativeObject() val opt = options as? NativeObject ?: newNativeObject()
scriptRuntime.images.colorFinder.findPointByColors( return scriptRuntime.images.colorFinder.findPointByColors(
image, image,
Colors.toIntRhino(firstColor), Colors.toIntRhino(firstColor),
parseThreshold(opt).roundToInt(), parseThreshold(opt).roundToInt(),
@@ -968,22 +983,16 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
}.toIntArray(), }.toIntArray(),
) )
} finally { } finally {
image.shoot() ApiImages.shoot(imageRef)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByColors(image, firstColor, paths, options)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByColors(image, firstColor, paths, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { fun findMultiColors(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 3..4) { argList ->
val (o, _, paths) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByColorsRhino(scriptRuntime, argList, ::findMultiColors.name)
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)
} }
@JvmStatic @JvmStatic
@@ -1014,26 +1023,33 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findPointByImage(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList -> fun findPointByImage(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList ->
val (o, template, xOrOptions, y, width, height, thresholdArg) = argList findPointByImageRhino(scriptRuntime, argList, ::findPointByImage.name)
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(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) { @JvmStatic
image.shoot() fun findPointByImageRhino(scriptRuntime: ScriptRuntime, args: Array<out Any?>, funcName: String): OpencvPoint? {
"Argument \"template\" ${template.jsBrief()} for images.findPointByImage must be a ImageWrapper" val (oA, oB, xOrOptions, y, width, height, thresholdArg) = args
} var imageA: ImageWrapper? = null
var imageB: ImageWrapper? = null
try { try {
val image = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(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<Any>(coerceString(oB), true))?.oneShot() else oB
require(template is ImageWrapper) { "Argument \"template\" ${oB.jsBrief()} for images.$funcName must be a ImageWrapper" }
imageB = template
initOpenCvIfNeeded() initOpenCvIfNeeded()
when { return when {
argList.size > 2 && xOrOptions !is NativeObject -> { args.size > 2 && xOrOptions !is NativeObject -> {
val options = mapOf( val options = mapOf(
"region" to listOf(/* x = */ xOrOptions, y, width, height), "region" to listOf(/* x = */ xOrOptions, y, width, height),
"threshold" to thresholdArg, "threshold" to thresholdArg,
).toNativeObject() ).toNativeObject()
findPointByImage(scriptRuntime, arrayOf(image, template, options)) findPointByImageRhino(scriptRuntime, arrayOf(image, template, options), funcName)
} }
else -> { else -> {
val opt = when { val opt = when {
argList.size > 2 -> xOrOptions as? NativeObject args.size > 2 -> xOrOptions as? NativeObject
else -> null else -> null
} ?: newNativeObject() } ?: newNativeObject()
val weakThreshold = parseWeakThreshold(opt, 0.6).toFloat() val weakThreshold = parseWeakThreshold(opt, 0.6).toFloat()
@@ -1044,49 +1060,39 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
} }
} }
} finally { } finally {
ApiImages.shoot(image, template) ApiImages.shoot(imageA, imageB)
} }
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, options)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, options)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findImage(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..3) { fun findImage(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList ->
val (o, template) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByImageRhino(scriptRuntime, argList, ::findImage.name)
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)
} }
@Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, x, y, width, height, threshold)")) @Deprecated("Deprecated in Java", ReplaceWith("findPointByImage(image, template, x, y, width, height, threshold)"))
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun findImageInRegion(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { fun findImageInRegion(scriptRuntime: ScriptRuntime, args: Array<out Any?>): OpencvPoint? = ensureArgumentsLengthInRange(args, 2..7) { argList ->
val (o, template) = it @Suppress("DEPRECATION")
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o findPointByImageRhino(scriptRuntime, argList, ::findImageInRegion.name)
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)
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun matchTemplate(scriptRuntime: ScriptRuntime, args: Array<out Any?>): MatchingResult = ensureArgumentsLengthInRange(args, 2..3) { fun matchTemplate(scriptRuntime: ScriptRuntime, args: Array<out Any?>): MatchingResult = ensureArgumentsLengthInRange(args, 2..3) {
val (o, template, options) = it val (oA, oB, options) = it
val image = if (o.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(o), true))?.oneShot() else o var imageA: ImageWrapper? = null
require(image is ImageWrapper) { "Argument \"image\" ${image.jsBrief()} for images.matchTemplate must be a ImageWrapper" } var imageB: ImageWrapper? = null
require(template is ImageWrapper) {
image.shoot()
"Argument \"template\" ${template.jsBrief()} for images.matchTemplate must be a ImageWrapper"
}
try { try {
val image = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(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<Any>(coerceString(oB), true))?.oneShot() else oB
require(template is ImageWrapper) { "Argument \"template\" ${template.jsBrief()} for images.matchTemplate must be a ImageWrapper" }
imageB = template
initOpenCvIfNeeded() initOpenCvIfNeeded()
val opt = options as? NativeObject ?: newNativeObject() val opt = options as? NativeObject ?: newNativeObject()
val weakThreshold = parseWeakThreshold(opt, 0.6).toFloat() 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)) MatchingResult(scriptRuntime.images.matchTemplate(image, template, weakThreshold, threshold, region, level, max, useTransparentMask))
} finally { } finally {
ApiImages.shoot(image, template) ApiImages.shoot(imageA, imageB)
} }
} }
@@ -1452,17 +1458,18 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun isEqual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 2) { argList -> fun isEqual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 2) { argList ->
val (oA, oB) = argList val (oA, oB) = argList
val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(oA), true))?.oneShot() else oA var imageARef: ImageWrapper? = null
require(imageA is ImageWrapper) { "Argument \"imageA\" ${imageA.jsBrief()} for images.isEqual must be a ImageWrapper}" } var imageBRef: ImageWrapper? = null
val imageB = if (oB.isJsString()) read(scriptRuntime, arrayOf<Any>(coerceString(oB), true))?.oneShot() else oB
require(imageB is ImageWrapper) {
imageA.shoot()
"Argument \"imageB\" ${imageB.jsBrief()} for images.isEqual must be a ImageWrapper"
}
try { try {
val imageA = if (oA.isJsString()) read(scriptRuntime, arrayOf<Any>(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<Any>(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) ImageSimilarity.isEqual(imageA.mat, imageB.mat)
} finally { } finally {
ApiImages.shoot(imageA, imageB) ApiImages.shoot(imageARef, imageBRef)
} }
} }

View File

@@ -37,7 +37,7 @@ class CrashHandler(private val errorReportClass: Class<*>) : CrashHandleCallback
if (crashTooManyTimes()) { if (crashTooManyTimes()) {
return super.onCrashHandleStart(crashType, errorType, errorMessage, errorStack) return super.onCrashHandleStart(crashType, errorType, errorMessage, errorStack)
} }
startErrorReportActivity("$errorType: $errorMessage", errorStack ?: "[ No stack message ]") startCrashReportActivity("$errorType: $errorMessage", errorStack ?: "[ No stack message ]")
} catch (e: Throwable) { } catch (e: Throwable) {
e.printStackTrace() e.printStackTrace()
} }
@@ -79,7 +79,7 @@ class CrashHandler(private val errorReportClass: Class<*>) : CrashHandleCallback
mBuglyHandler = buglyHandler mBuglyHandler = buglyHandler
} }
private fun startErrorReportActivity(msg: String, detail: String) { private fun startCrashReportActivity(msg: String, detail: String) {
Intent(GlobalAppContext.get(), errorReportClass).apply { Intent(GlobalAppContext.get(), errorReportClass).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
putExtra("message", msg) putExtra("message", msg)

View File

@@ -16,9 +16,9 @@ import org.autojs.autojs6.databinding.ActivityErrorReportBinding
* Created by Stardust on Feb 2, 2017. * Created by Stardust on Feb 2, 2017.
* Transformed by SuperMonster003 on Mar 10, 2025. * 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") @SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -29,7 +29,7 @@ class ErrorReportActivity : BaseActivity() {
appendLine(briefOfCurrentVersionInt(true)) appendLine(briefOfCurrentVersionInt(true))
intent.getStringExtra("message")?.let { appendLine().appendLine(it.trimEnd()) } intent.getStringExtra("message")?.let { appendLine().appendLine(it.trimEnd()) }
intent.getStringExtra("error")?.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 { val binding = ActivityErrorReportBinding.inflate(layoutInflater).also {
setContentView(it.root) setContentView(it.root)
@@ -62,7 +62,7 @@ class ErrorReportActivity : BaseActivity() {
@SuppressLint("MissingSuperCall") @SuppressLint("MissingSuperCall")
override fun onBackPressed() = exit() override fun onBackPressed() = exit()
private fun copy() = ClipboardUtils.setClip(this, errorMessage) private fun copy() = ClipboardUtils.setClip(this, crashMessage)
private fun exit() = finishAffinity() private fun exit() = finishAffinity()

View File

@@ -1,5 +1,5 @@
#Sat Jun 28 19:48:58 CST 2025 #Tue Jul 01 00:19:56 CST 2025
BUILD_TIME=1751111338507 BUILD_TIME=1751300396808
COMPILE_SDK_VERSION=35 COMPILE_SDK_VERSION=35
IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125 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 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3
TARGET_SDK_VERSION=35 TARGET_SDK_VERSION=35
TARGET_SDK_VERSION_INRT=29 TARGET_SDK_VERSION_INRT=29
VERSION_BUILD=3308 VERSION_BUILD=3312
VERSION_NAME=6.7.0 Alpha2 VERSION_NAME=6.7.0 Alpha2
VSCODE_EXT_REQUIRED_VERSION=1.0.8 VSCODE_EXT_REQUIRED_VERSION=1.0.8