6.7.0 - Alpha13 - 修复 images.save 及 ImageWrapper#saveTo 方法传入路径不存在时无法正常写入文件的问题

This commit is contained in:
SuperMonster003
2026-01-03 20:19:02 +08:00
parent b50a82cad6
commit f243a5fd23
5 changed files with 35 additions and 13 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$data": { "$data": {
"v6.7.0": { "v6.7.0": {
"released_date": "2025/12/31", "released_date": "2026/01/03",
"feature": [ "feature": [
"插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮)", "插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮)",
"cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))", "cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
@@ -30,7 +30,7 @@
"选择器的正则表达式参数支持使用标志 (i, m, s, u)", "选择器的正则表达式参数支持使用标志 (i, m, s, u)",
"正则表达式支持后瞻断言语法 _[`issue #464`](http://issues.autojs6.com/464)_", "正则表达式支持后瞻断言语法 _[`issue #464`](http://issues.autojs6.com/464)_",
"设置页面增加 \"Java 原始类型包装\" 设置选项 _[`issue #435`](http://issues.autojs6.com/435)_", "设置页面增加 \"Java 原始类型包装\" 设置选项 _[`issue #435`](http://issues.autojs6.com/435)_",
"设置页面增加 \"定时任务调度引擎\" 设置选项, 支持 AlarmManager/WorkManager/JobScheduler _[`issue #457`](http://issues.autojs6.com/457)_ _[`issue #449`](http://issues.autojs6.com/449)_ _[`issue #388`](http://issues.autojs6.com/388)_ _[`issue #163`](http://issues.autojs6.com/163)_ _[`issue #53`](http://issues.autojs6.com/53)_ _[`issue #21`](http://issues.autojs6.com/21)_", "设置页面增加 \"定时任务调度引擎\" 设置选项, 支持 AlarmManager/WorkManager/JobScheduler _[`issue #457`](http://issues.autojs6.com/457)_ _[`issue #434`](http://issues.autojs6.com/434)_ _[`issue #449`](http://issues.autojs6.com/449)_ _[`issue #388`](http://issues.autojs6.com/388)_ _[`issue #163`](http://issues.autojs6.com/163)_ _[`issue #53`](http://issues.autojs6.com/53)_ _[`issue #21`](http://issues.autojs6.com/21)_",
"设置页面增加 \"应用启动器图标\" 设置选项, 支持自适应图标/透明背景图标 _[`issue #405`](http://issues.autojs6.com/405)_", "设置页面增加 \"应用启动器图标\" 设置选项, 支持自适应图标/透明背景图标 _[`issue #405`](http://issues.autojs6.com/405)_",
"设置页面增加 \"重启策略\" 设置选项, 用于设置主页抽屉栏重启按钮是否使用快速重启策略", "设置页面增加 \"重启策略\" 设置选项, 用于设置主页抽屉栏重启按钮是否使用快速重启策略",
"设置页面启动器快捷方式增加 \"插件\" 选项, 用于通过快捷方式跳转到插件中心页面", "设置页面启动器快捷方式增加 \"插件\" 选项, 用于通过快捷方式跳转到插件中心页面",
@@ -57,11 +57,13 @@
"images 部分方法使用区域参数时 1 被误解析为百分比的问题", "images 部分方法使用区域参数时 1 被误解析为百分比的问题",
"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)_", "images 部分相关方法可能引发内存泄露的问题 _[`issue #372`](http://issues.autojs6.com/372)_",
"images.save 及 ImageWrapper#saveTo 方法传入路径不存在时无法正常写入文件的问题",
"ocr 部分重载方法可能无法正常使用的问题", "ocr 部分重载方法可能无法正常使用的问题",
"ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题 _[`issue #468`](http://issues.autojs6.com/468)_", "ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题 _[`issue #468`](http://issues.autojs6.com/468)_",
"auto.registerEvent 注册的无障碍服务事件会被其他脚本误清理的问题 _[`issue #466`](http://issues.autojs6.com/466)_", "auto.registerEvent 注册的无障碍服务事件会被其他脚本误清理的问题 _[`issue #466`](http://issues.autojs6.com/466)_ _[`issue #343`](http://issues.autojs6.com/343#issuecomment-3263953918)_",
"Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_", "Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_",
"运行项目时 project.json 配置参数无法正常解析的问题", "运行项目时 project.json 配置参数可能无法正常解析的问题",
"项目打包时 project.json 的 excludedDirs 配置参数将导致配置文件解析失败的问题 _[`issue #428`](http://issues.autojs6.com/428)_",
"项目配置文件中构建版本号或构建时间出现较大数字时可能导致应用崩溃的问题", "项目配置文件中构建版本号或构建时间出现较大数字时可能导致应用崩溃的问题",
"频繁获取或重建 ImageReader 时可能因缓冲区暂无可用帧导致应用崩溃的问题", "频繁获取或重建 ImageReader 时可能因缓冲区暂无可用帧导致应用崩溃的问题",
"输入事件观察器 InputEventObserver 可能导致应用启动时明显卡顿的问题", "输入事件观察器 InputEventObserver 可能导致应用启动时明显卡顿的问题",

View File

@@ -9,6 +9,7 @@ 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.extension.AnyExtensions.toRuntimePath
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
@@ -19,6 +20,7 @@ import org.opencv.core.CvType
import org.opencv.core.Size import org.opencv.core.Size
import org.opencv.imgcodecs.Imgcodecs import org.opencv.imgcodecs.Imgcodecs
import org.opencv.imgproc.Imgproc import org.opencv.imgproc.Imgproc
import java.io.File
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
@@ -152,7 +154,14 @@ open class ImageWrapper : Shootable<ImageWrapper> {
fun saveTo(path: String): Boolean { fun saveTo(path: String): Boolean {
ensureNotRecycled() ensureNotRecycled()
val fullPath = mScriptRuntime.files.nonNullPath(path) val fullPath = path.toRuntimePath(mScriptRuntime, true)
val file = File(fullPath)
val parentFile = file.parentFile
if (parentFile != null && !parentFile.exists()) {
if (!parentFile.mkdirs()) {
throw RuntimeException("Failed to create directory: ${parentFile.absolutePath}")
}
}
if (mBitmap == null) { if (mBitmap == null) {
if (mMat != null) { if (mMat != null) {
return Imgcodecs.imwrite(fullPath, mMat) return Imgcodecs.imwrite(fullPath, mMat)
@@ -162,11 +171,10 @@ open class ImageWrapper : Shootable<ImageWrapper> {
return runCatching { saveWithBitmap(fullPath) }.isSuccess return runCatching { saveWithBitmap(fullPath) }.isSuccess
} }
private fun saveWithBitmap(fullPath: String?) { private fun saveWithBitmap(fullPath: String) {
try { try {
fullPath ?: throw Exception("Argument \"path\" cannot be null") val bitmap = mBitmap ?: throw Exception("Member \"bitmap\" cannot be null")
mBitmap ?: throw Exception("Member \"bitmap\" cannot be null") bitmap.compress(CompressFormat.PNG, 100, FileOutputStream(fullPath))
mBitmap!!.compress(CompressFormat.PNG, 100, FileOutputStream(fullPath))
} catch (e: FileNotFoundException) { } catch (e: FileNotFoundException) {
throw UncheckedIOException(e) throw UncheckedIOException(e)
} }

View File

@@ -132,6 +132,8 @@ object AnyExtensions {
fun Any?.jsBrief() = "${Context.toString(this)} (${this.jsSpecies()})" fun Any?.jsBrief() = "${Context.toString(this)} (${this.jsSpecies()})"
@JvmStatic
@JvmOverloads
fun Any?.toRuntimePath(scriptRuntime: ScriptRuntime, isStrict: Boolean = false): String { fun Any?.toRuntimePath(scriptRuntime: ScriptRuntime, isStrict: Boolean = false): String {
if (isStrict && this.isJsNullish()) throw IllegalArgumentException(str(R.string.error_cannot_convert_value_into_a_script_runtime_path, this.jsBrief())) if (isStrict && this.isJsNullish()) throw IllegalArgumentException(str(R.string.error_cannot_convert_value_into_a_script_runtime_path, this.jsBrief()))
return scriptRuntime.files.nonNullPath(coerceString(this, ".")) return scriptRuntime.files.nonNullPath(coerceString(this, "."))

View File

@@ -1,5 +1,6 @@
package org.autojs.autojs.runtime.api; package org.autojs.autojs.runtime.api;
import org.autojs.autojs.extension.AnyExtensions;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -49,6 +50,7 @@ import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc; import org.opencv.imgproc.Imgproc;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -298,7 +300,15 @@ public class Images {
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 { try {
return saveInternal(image, path, format, quality); var nicePath = AnyExtensions.toRuntimePath(path, mScriptRuntime, true);
var file = new File(nicePath);
File parentFile = file.getParentFile();
if (parentFile != null && !parentFile.exists()) {
if (!parentFile.mkdirs()) {
throw new IOException("Failed to create parent directory for image save: " + parentFile.getAbsolutePath());
}
}
return saveInternal(image, nicePath, format, quality);
} finally { } finally {
shoot(image); shoot(image);
} }

View File

@@ -1,5 +1,5 @@
#Wed Dec 31 20:04:55 CST 2025 #Sat Jan 03 20:14:36 CST 2026
BUILD_TIME=1767182695685 BUILD_TIME=1767442476618
COMPILE_SDK_VERSION=36 COMPILE_SDK_VERSION=36
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
@@ -27,6 +27,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=36 TARGET_SDK_VERSION=36
TARGET_SDK_VERSION_INRT=29 TARGET_SDK_VERSION_INRT=29
VERSION_BUILD=3572 VERSION_BUILD=3576
VERSION_NAME=6.7.0 Alpha13 VERSION_NAME=6.7.0 Alpha13
VSCODE_EXT_REQUIRED_VERSION=1.0.8 VSCODE_EXT_REQUIRED_VERSION=1.0.8