6.7.0 - Alpha - 修复 images 模块相关方法出现异常时 oneShot 标记功能失效的问题 (issue #372)
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"$data": {
|
"$data": {
|
||||||
"v6.7.0": {
|
"v6.7.0": {
|
||||||
"released_date": "2025/06/08",
|
"released_date": "2025/06/10",
|
||||||
"feature": [
|
"feature": [
|
||||||
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))"
|
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))"
|
||||||
],
|
],
|
||||||
"fix": [
|
"fix": [
|
||||||
"使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题",
|
"使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题",
|
||||||
"调用 images.requestScreenCapture 时用户取消授权可能导致应用崩溃的问题",
|
"调用 images.requestScreenCapture 时用户取消授权可能导致应用崩溃的问题",
|
||||||
|
"images 部分相关方法出现异常时 oneShot 标记功能失效的问题 _[`issue #372`](http://issues.autojs6.com/372)_",
|
||||||
"版本历史页面部分系统因字体差别导致统计数据显示不完整的问题"
|
"版本历史页面部分系统因字体差别导致统计数据显示不完整的问题"
|
||||||
],
|
],
|
||||||
"improvement": [],
|
"improvement": [],
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ 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 : Recyclable, MonitorResource {
|
open class ImageWrapper : Shootable<ImageWrapper>, MonitorResource {
|
||||||
|
|
||||||
private var mScriptRuntime: ScriptRuntime
|
private var mScriptRuntime: ScriptRuntime
|
||||||
|
|
||||||
@@ -62,36 +62,44 @@ open class ImageWrapper : Recyclable, MonitorResource {
|
|||||||
val size
|
val size
|
||||||
get() = Size(mWidth.toDouble(), mHeight.toDouble()).also { ensureNotRecycled() }
|
get() = Size(mWidth.toDouble(), mHeight.toDouble()).also { ensureNotRecycled() }
|
||||||
|
|
||||||
val bitmap by lazy {
|
val bitmap: Bitmap
|
||||||
ensureNotRecycled()
|
get() {
|
||||||
if (mBitmap == null) {
|
ensureNotRecycled()
|
||||||
if (mMat != null) {
|
if (mBitmap == null) {
|
||||||
mBitmap = createBitmap(mMat!!.width(), mMat!!.height())
|
val mat = mMat
|
||||||
Utils.matToBitmap(mMat, mBitmap)
|
if (mat != null) {
|
||||||
} else {
|
val bitmap = createBitmap(mat.width(), mat.height()).also { mBitmap = it }
|
||||||
mBitmap = mediaImage?.let { toBitmap(it) }
|
Utils.matToBitmap(mat, bitmap)
|
||||||
|
} else {
|
||||||
|
val mediaImage = mediaImage
|
||||||
|
if (mediaImage != null) {
|
||||||
|
mBitmap = toBitmap(mediaImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return mBitmap ?: throw Exception("Bitmap of ImageWrapper should never be null")
|
||||||
}
|
}
|
||||||
return@lazy mBitmap ?: throw Exception("Bitmap of ImageWrapper should never be null")
|
|
||||||
}
|
|
||||||
|
|
||||||
val mat by lazy {
|
val mat: Mat
|
||||||
ensureNotRecycled()
|
get() {
|
||||||
if (mMat != null) {
|
ensureNotRecycled()
|
||||||
return@lazy mMat!!
|
val mat = mMat
|
||||||
|
if (mat != null) {
|
||||||
|
return mat
|
||||||
|
}
|
||||||
|
val bitmap = mBitmap
|
||||||
|
if (bitmap != null) {
|
||||||
|
val newMat = Mat().also { mMat = it }
|
||||||
|
Utils.bitmapToMat(bitmap, newMat)
|
||||||
|
return newMat
|
||||||
|
}
|
||||||
|
if (mediaImage != 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 }
|
||||||
|
}
|
||||||
|
throw AssertionError("Both bitmap and image are null")
|
||||||
}
|
}
|
||||||
if (mBitmap != null) {
|
|
||||||
mMat = Mat()
|
|
||||||
Utils.bitmapToMat(mBitmap, mMat)
|
|
||||||
return@lazy mMat!!
|
|
||||||
}
|
|
||||||
if (mediaImage != null) {
|
|
||||||
val plane = plane ?: throw AssertionError("Image plain is null")
|
|
||||||
plane.buffer.position(0)
|
|
||||||
return@lazy Mat(mHeight, mWidth, CvType.CV_8UC4, plane.buffer, plane.rowStride.toLong()).also { mMat = it }
|
|
||||||
}
|
|
||||||
throw AssertionError("Both bitmap and image are null")
|
|
||||||
}
|
|
||||||
|
|
||||||
val bgrMat
|
val bgrMat
|
||||||
get() = Mat().also {
|
get() = Mat().also {
|
||||||
@@ -308,7 +316,7 @@ open class ImageWrapper : Recyclable, MonitorResource {
|
|||||||
fun recycleAll() {
|
fun recycleAll() {
|
||||||
imageList.forEach {
|
imageList.forEach {
|
||||||
when (val o = it.get()) {
|
when (val o = it.get()) {
|
||||||
is Recyclable -> o.recycle()
|
is Shootable<*> -> o.recycle()
|
||||||
is Bitmap -> o.recycle()
|
is Bitmap -> o.recycle()
|
||||||
is org.opencv.core.Mat -> OpenCVHelper.release(o)
|
is org.opencv.core.Mat -> OpenCVHelper.release(o)
|
||||||
is Image -> o.close()
|
is Image -> o.close()
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package org.autojs.autojs.core.image;
|
package org.autojs.autojs.core.image;
|
||||||
|
|
||||||
public interface Recyclable {
|
public interface Shootable<T> {
|
||||||
|
|
||||||
void recycle();
|
void recycle();
|
||||||
|
|
||||||
boolean isRecycled();
|
boolean isRecycled();
|
||||||
|
|
||||||
ImageWrapper setOneShot(boolean b);
|
T setOneShot(boolean b);
|
||||||
|
|
||||||
default ImageWrapper oneShot() {
|
default T oneShot() {
|
||||||
return setOneShot(true);
|
return setOneShot(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.autojs.autojs.annotation.ScriptVariable;
|
|||||||
import org.autojs.autojs.concurrent.VolatileDispose;
|
import org.autojs.autojs.concurrent.VolatileDispose;
|
||||||
import org.autojs.autojs.core.image.CapturedImage;
|
import org.autojs.autojs.core.image.CapturedImage;
|
||||||
import org.autojs.autojs.core.image.ImageWrapper;
|
import org.autojs.autojs.core.image.ImageWrapper;
|
||||||
|
import org.autojs.autojs.core.image.Shootable;
|
||||||
import org.autojs.autojs.core.image.RhinoColorFinder;
|
import org.autojs.autojs.core.image.RhinoColorFinder;
|
||||||
import org.autojs.autojs.core.image.TemplateMatching;
|
import org.autojs.autojs.core.image.TemplateMatching;
|
||||||
import org.autojs.autojs.core.image.capture.ScreenCaptureRequester;
|
import org.autojs.autojs.core.image.capture.ScreenCaptureRequester;
|
||||||
@@ -56,6 +57,7 @@ import java.net.URL;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static org.autojs.autojs.util.RhinoUtils.isMainThread;
|
import static org.autojs.autojs.util.RhinoUtils.isMainThread;
|
||||||
@@ -153,12 +155,22 @@ public class Images {
|
|||||||
if (image == null) {
|
if (image == null) {
|
||||||
throw new NullPointerException(str(R.string.error_method_called_with_null_argument, "Images.pixel", "image"));
|
throw new NullPointerException(str(R.string.error_method_called_with_null_argument, "Images.pixel", "image"));
|
||||||
}
|
}
|
||||||
int pixel = image.pixel(x, y);
|
try {
|
||||||
image.shoot();
|
return image.pixel(x, y);
|
||||||
return pixel;
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImageWrapper concat(ScriptRuntime scriptRuntime, ImageWrapper imgA, ImageWrapper imgB, int direction) {
|
public static ImageWrapper concat(ScriptRuntime scriptRuntime, ImageWrapper imgA, ImageWrapper imgB, int direction) {
|
||||||
|
try {
|
||||||
|
return concatInternal(scriptRuntime, imgA, imgB, direction);
|
||||||
|
} finally {
|
||||||
|
shoot(imgA, imgB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImageWrapper concatInternal(ScriptRuntime scriptRuntime, ImageWrapper imgA, ImageWrapper imgB, int direction) {
|
||||||
if (!Arrays.asList(Gravity.START, Gravity.END, Gravity.TOP, Gravity.BOTTOM).contains(direction)) {
|
if (!Arrays.asList(Gravity.START, Gravity.END, Gravity.TOP, Gravity.BOTTOM).contains(direction)) {
|
||||||
throw new IllegalArgumentException(str(R.string.error_illegal_argument, "direction", direction));
|
throw new IllegalArgumentException(str(R.string.error_illegal_argument, "direction", direction));
|
||||||
}
|
}
|
||||||
@@ -186,8 +198,6 @@ public class Images {
|
|||||||
canvas.drawBitmap(imgA.getBitmap(), (float) (width - imgA.getWidth()) / 2, 0, paint);
|
canvas.drawBitmap(imgA.getBitmap(), (float) (width - imgA.getWidth()) / 2, 0, paint);
|
||||||
canvas.drawBitmap(imgB.getBitmap(), (float) (width - imgB.getWidth()) / 2, imgA.getHeight(), paint);
|
canvas.drawBitmap(imgB.getBitmap(), (float) (width - imgB.getWidth()) / 2, imgA.getHeight(), paint);
|
||||||
}
|
}
|
||||||
imgA.shoot();
|
|
||||||
imgB.shoot();
|
|
||||||
return ImageWrapper.ofBitmap(scriptRuntime, bitmap);
|
return ImageWrapper.ofBitmap(scriptRuntime, bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,12 +289,22 @@ public class Images {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper copy(@NonNull ImageWrapper image) {
|
public ImageWrapper copy(@NonNull ImageWrapper image) {
|
||||||
ImageWrapper imageWrapper = image.clone();
|
try {
|
||||||
image.shoot();
|
return image.clone();
|
||||||
return imageWrapper;
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean save(@NonNull ImageWrapper image, @NonNull String path, @NonNull String format, int quality) throws IOException {
|
public boolean save(@NonNull ImageWrapper image, @NonNull String path, @NonNull String format, int quality) throws IOException {
|
||||||
|
try {
|
||||||
|
return saveInternal(image, path, format, quality);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean saveInternal(@NonNull ImageWrapper image, @NonNull String path, @NonNull String format, int quality) throws IOException {
|
||||||
Bitmap bitmap = image.getBitmap();
|
Bitmap bitmap = image.getBitmap();
|
||||||
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
||||||
|
|
||||||
@@ -306,19 +326,24 @@ public class Images {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(path)) {
|
try (FileOutputStream fos = new FileOutputStream(path)) {
|
||||||
boolean b = bitmap.compress(compressFormat, quality, fos);
|
return bitmap.compress(compressFormat, quality, fos);
|
||||||
image.shoot();
|
|
||||||
return b;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] compressToBytes(@NotNull ImageWrapper image, @NotNull String format, int quality) {
|
public byte[] compressToBytes(@NotNull ImageWrapper image, @NotNull String format, int quality) {
|
||||||
|
try {
|
||||||
|
return compressToBytesInternal(image, format, quality);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] compressToBytesInternal(@NotNull ImageWrapper image, @NotNull String format, int quality) {
|
||||||
Bitmap bitmap = image.getBitmap();
|
Bitmap bitmap = image.getBitmap();
|
||||||
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
||||||
|
|
||||||
if (compressFormat == Bitmap.CompressFormat.PNG && quality != 100) {
|
if (compressFormat == Bitmap.CompressFormat.PNG && quality != 100) {
|
||||||
byte[] compressed = PngQuantBridge.quantize(bitmap, quality);
|
byte[] compressed = PngQuantBridge.quantize(bitmap, quality);
|
||||||
image.shoot();
|
|
||||||
if (compressed != null) {
|
if (compressed != null) {
|
||||||
return compressed;
|
return compressed;
|
||||||
}
|
}
|
||||||
@@ -327,14 +352,12 @@ public class Images {
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
if (compressFormat == Bitmap.CompressFormat.WEBP_LOSSLESS && quality != 100) {
|
if (compressFormat == Bitmap.CompressFormat.WEBP_LOSSLESS && quality != 100) {
|
||||||
image.shoot();
|
|
||||||
throw new IllegalArgumentException(mContext.getString(R.string.error_webp_lossless_quality_not_supported));
|
throw new IllegalArgumentException(mContext.getString(R.string.error_webp_lossless_quality_not_supported));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
bitmap.compress(compressFormat, quality, outputStream);
|
bitmap.compress(compressFormat, quality, outputStream);
|
||||||
image.shoot();
|
|
||||||
return outputStream.toByteArray();
|
return outputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,17 +375,31 @@ public class Images {
|
|||||||
releaseScreenCapturer();
|
releaseScreenCapturer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper rotate(@NonNull ImageWrapper img, float x, float y, float degree) {
|
public ImageWrapper rotate(@NonNull ImageWrapper image, float x, float y, float degree) {
|
||||||
|
try {
|
||||||
|
return rotateInternal(image, x, y, degree);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageWrapper rotateInternal(@NonNull ImageWrapper image, float x, float y, float degree) {
|
||||||
Matrix matrix = new Matrix();
|
Matrix matrix = new Matrix();
|
||||||
matrix.postRotate(degree, x, y);
|
matrix.postRotate(degree, x, y);
|
||||||
ImageWrapper imageWrapper = ImageWrapper.ofBitmap(mScriptRuntime, Bitmap.createBitmap(img.getBitmap(), 0, 0, img.getWidth(), img.getHeight(), matrix, true));
|
return ImageWrapper.ofBitmap(mScriptRuntime, Bitmap.createBitmap(image.getBitmap(), 0, 0, image.getWidth(), image.getHeight(), matrix, true));
|
||||||
img.shoot();
|
|
||||||
return imageWrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ScriptInterface
|
@ScriptInterface
|
||||||
public ImageWrapper flip(@NonNull ImageWrapper img, boolean horizontal, boolean vertical) {
|
public ImageWrapper flip(@NonNull ImageWrapper image, boolean horizontal, boolean vertical) {
|
||||||
Bitmap original = img.getBitmap();
|
try {
|
||||||
|
return flipInternal(image, horizontal, vertical);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageWrapper flipInternal(@NonNull ImageWrapper image, boolean horizontal, boolean vertical) {
|
||||||
|
Bitmap original = image.getBitmap();
|
||||||
Matrix matrix = new Matrix();
|
Matrix matrix = new Matrix();
|
||||||
|
|
||||||
// Set scaling ratio according to input parameters.
|
// Set scaling ratio according to input parameters.
|
||||||
@@ -380,14 +417,19 @@ public class Images {
|
|||||||
if (vertical) matrix.postTranslate(0, original.getHeight());
|
if (vertical) matrix.postTranslate(0, original.getHeight());
|
||||||
|
|
||||||
Bitmap flipped = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
|
Bitmap flipped = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
|
||||||
img.shoot();
|
|
||||||
return ImageWrapper.ofBitmap(mScriptRuntime, flipped);
|
return ImageWrapper.ofBitmap(mScriptRuntime, flipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper clip(@NonNull ImageWrapper img, int x, int y, int w, int h) {
|
public ImageWrapper clip(@NonNull ImageWrapper image, int x, int y, int w, int h) {
|
||||||
ImageWrapper imageWrapper = ImageWrapper.ofBitmap(mScriptRuntime, Bitmap.createBitmap(img.getBitmap(), x, y, w, h));
|
try {
|
||||||
img.shoot();
|
return clipInternal(image, x, y, w, h);
|
||||||
return imageWrapper;
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageWrapper clipInternal(@NonNull ImageWrapper image, int x, int y, int w, int h) {
|
||||||
|
return ImageWrapper.ofBitmap(mScriptRuntime, Bitmap.createBitmap(image.getBitmap(), x, y, w, h));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper read(String path) {
|
public ImageWrapper read(String path) {
|
||||||
@@ -416,25 +458,32 @@ public class Images {
|
|||||||
return ImageWrapper.ofBitmap(mScriptRuntime, Drawables.loadBase64Data(data));
|
return ImageWrapper.ofBitmap(mScriptRuntime, Drawables.loadBase64Data(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toBase64(ImageWrapper img, String format, int quality) {
|
public String toBase64(ImageWrapper image, String format, int quality) {
|
||||||
byte[] input = toBytes(img, format, quality);
|
try {
|
||||||
img.shoot();
|
byte[] input = toBytes(image, format, quality);
|
||||||
return Base64.encodeToString(input, Base64.NO_WRAP);
|
return Base64.encodeToString(input, Base64.NO_WRAP);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toBytes(@NonNull ImageWrapper img, String format, int quality) {
|
public byte[] toBytes(@NonNull ImageWrapper image, String format, int quality) {
|
||||||
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
try {
|
||||||
Bitmap bitmap = img.getBitmap();
|
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
Bitmap bitmap = image.getBitmap();
|
||||||
bitmap.compress(compressFormat, quality, outputStream);
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
img.shoot();
|
bitmap.compress(compressFormat, quality, outputStream);
|
||||||
return outputStream.toByteArray();
|
return outputStream.toByteArray();
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper fromBytes(byte[] bytes) throws BitmapUtils.DecodeException {
|
public ImageWrapper fromBytes(byte[] bytes) throws BitmapUtils.DecodeException {
|
||||||
return ImageWrapper.ofBitmap(mScriptRuntime, BitmapUtils.bitmapFromByteArrayOrThrow(bytes));
|
return ImageWrapper.ofBitmap(mScriptRuntime, BitmapUtils.bitmapFromByteArrayOrThrow(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @noinspection deprecation */
|
||||||
private Bitmap.CompressFormat parseImageFormat(String format) {
|
private Bitmap.CompressFormat parseImageFormat(String format) {
|
||||||
return switch (format.toLowerCase(Language.getPrefLanguage().getLocale())) {
|
return switch (format.toLowerCase(Language.getPrefLanguage().getLocale())) {
|
||||||
case "png" -> Bitmap.CompressFormat.PNG;
|
case "png" -> Bitmap.CompressFormat.PNG;
|
||||||
@@ -468,6 +517,14 @@ public class Images {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ImageWrapper invert(@NonNull ImageWrapper image) {
|
public ImageWrapper invert(@NonNull ImageWrapper image) {
|
||||||
|
try {
|
||||||
|
return invertInternal(image);
|
||||||
|
} finally {
|
||||||
|
shoot(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageWrapper invertInternal(@NonNull ImageWrapper image) {
|
||||||
initOpenCvIfNeeded();
|
initOpenCvIfNeeded();
|
||||||
|
|
||||||
Bitmap originalBitmap = image.getBitmap();
|
Bitmap originalBitmap = image.getBitmap();
|
||||||
@@ -503,8 +560,6 @@ public class Images {
|
|||||||
Bitmap invertedBitmap = Bitmap.createBitmap(originalWidth, originalHeight, Bitmap.Config.ARGB_8888);
|
Bitmap invertedBitmap = Bitmap.createBitmap(originalWidth, originalHeight, Bitmap.Config.ARGB_8888);
|
||||||
Utils.matToBitmap(destMat, invertedBitmap);
|
Utils.matToBitmap(destMat, invertedBitmap);
|
||||||
|
|
||||||
image.shoot();
|
|
||||||
|
|
||||||
return ImageWrapper.ofBitmap(mScriptRuntime, invertedBitmap);
|
return ImageWrapper.ofBitmap(mScriptRuntime, invertedBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,6 +612,14 @@ public class Images {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@ScriptInterface
|
@ScriptInterface
|
||||||
public Point findImage(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel) throws Exception {
|
public Point findImage(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel) throws Exception {
|
||||||
|
try {
|
||||||
|
return findImageInternal(image, template, weakThreshold, strictThreshold, rect, maxLevel);
|
||||||
|
} finally {
|
||||||
|
shoot(image, template);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point findImageInternal(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel) throws Exception {
|
||||||
initOpenCvIfNeeded();
|
initOpenCvIfNeeded();
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.findImage", "image"));
|
throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.findImage", "image"));
|
||||||
@@ -588,8 +651,6 @@ public class Images {
|
|||||||
if (shouldReleaseMat) {
|
if (shouldReleaseMat) {
|
||||||
OpenCVHelper.release(src);
|
OpenCVHelper.release(src);
|
||||||
}
|
}
|
||||||
image.shoot();
|
|
||||||
template.shoot();
|
|
||||||
}
|
}
|
||||||
if (point != null) {
|
if (point != null) {
|
||||||
if (rect != null) {
|
if (rect != null) {
|
||||||
@@ -603,6 +664,14 @@ public class Images {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<TemplateMatching.Match> matchTemplate(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel, int limit, boolean useTransparentMask) {
|
public List<TemplateMatching.Match> matchTemplate(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel, int limit, boolean useTransparentMask) {
|
||||||
|
try {
|
||||||
|
return matchTemplateInternal(image, template, weakThreshold, strictThreshold, rect, maxLevel, limit, useTransparentMask);
|
||||||
|
} finally {
|
||||||
|
shoot(image, template);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TemplateMatching.Match> matchTemplateInternal(ImageWrapper image, ImageWrapper template, float weakThreshold, float strictThreshold, Rect rect, int maxLevel, int limit, boolean useTransparentMask) {
|
||||||
initOpenCvIfNeeded();
|
initOpenCvIfNeeded();
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.matchTemplate", "image"));
|
throw new NullPointerException(mContext.getString(R.string.error_method_called_with_null_argument, "Images.matchTemplate", "image"));
|
||||||
@@ -623,8 +692,6 @@ public class Images {
|
|||||||
if (src != image.getMat()) {
|
if (src != image.getMat()) {
|
||||||
OpenCVHelper.release(src);
|
OpenCVHelper.release(src);
|
||||||
}
|
}
|
||||||
image.shoot();
|
|
||||||
template.shoot();
|
|
||||||
|
|
||||||
for (TemplateMatching.Match match : result) {
|
for (TemplateMatching.Match match : result) {
|
||||||
Point point = match.point;
|
Point point = match.point;
|
||||||
@@ -669,4 +736,8 @@ public class Images {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void shoot(Shootable<?>... shootableArgs) {
|
||||||
|
Arrays.stream(shootableArgs).filter(Objects::nonNull).forEach(Shootable::shoot);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.autojs.autojs.runtime.api.augment.images
|
package org.autojs.autojs.runtime.api.augment.images
|
||||||
|
|
||||||
|
import org.autojs.autojs.core.image.Shootable
|
||||||
import org.autojs.autojs.runtime.api.ImageFeatureMatching
|
import org.autojs.autojs.runtime.api.ImageFeatureMatching
|
||||||
import org.autojs.autojs.util.RhinoUtils
|
import org.autojs.autojs.util.RhinoUtils
|
||||||
import org.mozilla.javascript.Undefined
|
import org.mozilla.javascript.Undefined
|
||||||
@@ -9,15 +10,28 @@ class ImageFeatures(
|
|||||||
@JvmField var javaObject: ImageFeatureMatching.FeatureMatchingDescriptor,
|
@JvmField var javaObject: ImageFeatureMatching.FeatureMatchingDescriptor,
|
||||||
@JvmField var scale: Float,
|
@JvmField var scale: Float,
|
||||||
@JvmField var region: Rect,
|
@JvmField var region: Rect,
|
||||||
) {
|
) : Shootable<ImageFeatures> {
|
||||||
|
|
||||||
|
private var mIsOneShot = false
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var recycled = false
|
var recycled = false
|
||||||
|
|
||||||
|
override fun isRecycled() = recycled
|
||||||
|
|
||||||
|
override fun setOneShot(b: Boolean): ImageFeatures {
|
||||||
|
mIsOneShot = b
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shoot() {
|
||||||
|
if (mIsOneShot) recycle()
|
||||||
|
}
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var onRecycled: ((ImageFeatures) -> Undefined) = { _: ImageFeatures -> RhinoUtils.UNDEFINED }
|
var onRecycled: ((ImageFeatures) -> Undefined) = { _: ImageFeatures -> RhinoUtils.UNDEFINED }
|
||||||
|
|
||||||
fun recycle() {
|
override fun recycle() {
|
||||||
if (!recycled) {
|
if (!recycled) {
|
||||||
javaObject.release()
|
javaObject.release()
|
||||||
onRecycled.invoke(this)
|
onRecycled.invoke(this)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
#Mon Jun 09 19:43:01 CST 2025
|
#Tue Jun 10 18:30:41 CST 2025
|
||||||
BUILD_TIME=1749469381134
|
BUILD_TIME=1749551441206
|
||||||
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=3286
|
VERSION_BUILD=3289
|
||||||
VERSION_NAME=6.7.0 Alpha
|
VERSION_NAME=6.7.0 Alpha
|
||||||
VSCODE_EXT_REQUIRED_VERSION=1.0.8
|
VSCODE_EXT_REQUIRED_VERSION=1.0.8
|
||||||
|
|||||||
Reference in New Issue
Block a user