ms-vite-plugin 1.4.49 → 1.4.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/build.js +1 -1
  2. package/dist/cli.js +1 -1
  3. package/dist/mcp/doc-tools.js +1 -1
  4. package/dist/mcp/docs-service.js +1 -1
  5. package/dist/mcp/types.d.ts +1 -1
  6. package/dist/mcp/types.js +1 -1
  7. package/dist/project.js +1 -1
  8. package/docs/AGENTS.md +3 -2
  9. package/docs/SKILL.md +2 -1
  10. package/docs/apilua/action.md +1013 -0
  11. package/docs/apilua/appleocr.md +281 -0
  12. package/docs/apilua/cloud.md +183 -0
  13. package/docs/apilua/config.md +181 -0
  14. package/docs/apilua/cryptoUtils.md +253 -0
  15. package/docs/apilua/device.md +485 -0
  16. package/docs/apilua/dotocr.md +230 -0
  17. package/docs/apilua/file.md +554 -0
  18. package/docs/apilua/global.md +654 -0
  19. package/docs/apilua/hid.md +1126 -0
  20. package/docs/apilua/hotUpdate.md +167 -0
  21. package/docs/apilua/http.md +427 -0
  22. package/docs/apilua/image.md +1177 -0
  23. package/docs/apilua/ime.md +283 -0
  24. package/docs/apilua/logger.md +294 -0
  25. package/docs/apilua/media.md +283 -0
  26. package/docs/apilua/mysql.md +445 -0
  27. package/docs/apilua/netCard.md +224 -0
  28. package/docs/apilua/node.md +264 -0
  29. package/docs/apilua/opencv.md +870 -0
  30. package/docs/apilua/paddleocr.md +324 -0
  31. package/docs/apilua/pip.md +359 -0
  32. package/docs/apilua/system.md +686 -0
  33. package/docs/apilua/tomatoocr.md +461 -0
  34. package/docs/apilua/tts.md +330 -0
  35. package/docs/apilua/ui.md +1033 -0
  36. package/docs/apilua/utils.md +222 -0
  37. package/docs/apilua/yolo.md +324 -0
  38. package/docs/apilua/yolocls.md +276 -0
  39. package/docs/mcp-agent-description.md +5 -4
  40. package/docs/quick/vscode/createProject.md +84 -0
  41. package/docs/quick/vscode/packProject.md +17 -0
  42. package/package.json +2 -1
@@ -0,0 +1,1177 @@
1
+ # 图片模块 (Image)
2
+
3
+ 图片模块提供了强大的图像处理功能,包括截图、图像识别、模板匹配、颜色查找、图像变换等。
4
+
5
+ 注意所有的 `imageId` 都需要在使用后释放,否则会导致内存泄漏。
6
+
7
+ 所有传递`imageId`的函数都可以使用`"screen"`作为参数,来表示对当前屏幕进行操作。
8
+
9
+ `"screen"` 在设置为`Agent`模式,使用`快点Agent`截图,录屏模式使用录屏截图。
10
+
11
+ 所有传递`imageId`的函数都可以使用`"shortcut"`作为参数,来表示指定 HID 快捷指令截图
12
+
13
+ 所有传递`imageId`的函数都可以使用`"actionScreenshot"`作为参数,来表示指定 HID 快捷键系统截图
14
+
15
+ 所有传递`imageId`的函数都可以使用图片路径作为参数,来表示对指定图片进行操作,支持 res 目录文件,和手机文件路径。
16
+
17
+ ## 图片获取与管理
18
+
19
+ ### captureScreen - 截取屏幕。
20
+
21
+ 坐标缺省 `0` 表示全屏。四个坐标都传 `0` 时与 `captureFullScreen` 相同。
22
+
23
+ ```lua
24
+ ---@param x number?
25
+ ---@param y number?
26
+ ---@param ex number?
27
+ ---@param ey number?
28
+ ---@return string|nil
29
+ function captureScreen(x, y, ex, ey) end
30
+ ```
31
+
32
+ **参数:**
33
+
34
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
35
+ | ------ | ------ | -------- | ------ | ----------------- |
36
+ | `x` | number | 否 | 0 | 区域左上角 X 坐标 |
37
+ | `y` | number | 否 | 0 | 区域左上角 Y 坐标 |
38
+ | `ex` | number | 否 | 0 | 区域右下角 X 坐标 |
39
+ | `ey` | number | 否 | 0 | 区域右下角 Y 坐标 |
40
+
41
+ **返回值:**
42
+
43
+ | 类型 | 描述 |
44
+ | --------------- | -------------------------------- |
45
+ | `string \| nil` | 截图的图片 ID,失败时返回 `nil` |
46
+
47
+ **示例:**
48
+
49
+ ```lua
50
+ local image = require("image")
51
+ local file = require("file")
52
+ local dir = file.getInternalDir("documents")
53
+
54
+ -- 全屏截图
55
+ local imageId = image.captureScreen()
56
+ if imageId then
57
+ image.saveTo(imageId, dir .. "/screenshot.jpg")
58
+ image.release(imageId)
59
+ end
60
+
61
+ -- 截取指定区域
62
+ local rectId = image.captureScreen(100, 100, 200, 200)
63
+ if rectId then
64
+ image.saveTo(rectId, dir .. "/rect.jpg")
65
+ image.release(rectId)
66
+ end
67
+ ```
68
+
69
+ ### captureFullScreen - 截取全屏。
70
+
71
+ ```lua
72
+ ---@return string|nil
73
+ function captureFullScreen() end
74
+ ```
75
+
76
+ **返回值:**
77
+
78
+ | 类型 | 描述 |
79
+ | --------------- | -------------------------------- |
80
+ | `string \| nil` | 截图的图片 ID,失败时返回 `nil` |
81
+
82
+ **示例:**
83
+
84
+ ```lua
85
+ local image = require("image")
86
+ local file = require("file")
87
+ local imageId = image.captureFullScreen()
88
+ local dir = file.getInternalDir("documents")
89
+ if imageId then
90
+ print("截图成功")
91
+ image.saveTo(imageId, dir .. "/screenshot.jpg")
92
+ image.release(imageId)
93
+ else
94
+ print("截图失败")
95
+ end
96
+ ```
97
+
98
+ ### captureRect - 截取指定区域。
99
+
100
+ ```lua
101
+ ---@param x number?
102
+ ---@param y number?
103
+ ---@param ex number?
104
+ ---@param ey number?
105
+ ---@return string|nil
106
+ function captureRect(x, y, ex, ey) end
107
+ ```
108
+
109
+ **参数:**
110
+
111
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
112
+ | ------ | ------ | -------- | ------ | ----------------- |
113
+ | `x` | number | 否 | 0 | 区域左上角 X 坐标 |
114
+ | `y` | number | 否 | 0 | 区域左上角 Y 坐标 |
115
+ | `ex` | number | 否 | 0 | 区域右下角 X 坐标 |
116
+ | `ey` | number | 否 | 0 | 区域右下角 Y 坐标 |
117
+
118
+ **返回值:**
119
+
120
+ | 类型 | 描述 |
121
+ | --------------- | -------------------------------- |
122
+ | `string \| nil` | 截图的图片 ID,失败时返回 `nil` |
123
+
124
+ **示例:**
125
+
126
+ ```lua
127
+ local image = require("image")
128
+ local file = require("file")
129
+ local imageId = image.captureRect(100, 100, 200, 200)
130
+ local dir = file.getInternalDir("documents")
131
+ if imageId then
132
+ print("截图成功")
133
+ image.saveTo(imageId, dir .. "/screenshot.jpg")
134
+ image.release(imageId)
135
+ else
136
+ print("截图失败")
137
+ end
138
+ ```
139
+
140
+ ### readImage - 从文件路径或imageId读取图片。
141
+
142
+ ```lua
143
+ ---@param path string
144
+ ---@return string | nil
145
+ function readImage(path) end
146
+ ```
147
+
148
+ **参数:**
149
+
150
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
151
+ | ------ | ------ | -------- | ------ | ----------------------------------------------------------------------- |
152
+ | `path` | string | 是 | - | 图片文件路径 支持 res 目录文件和手机文件绝对路径,支持特殊标识的imageId |
153
+
154
+ **返回值:**
155
+
156
+ | 类型 | 描述 |
157
+ | -------- | -------------------------- |
158
+ | `string` | 图片 ID,失败时返回 `nil` |
159
+
160
+ **示例:**
161
+
162
+ ```lua
163
+ local image = require("image")
164
+ local imageId = image.readImage("template.jpg")
165
+ if imageId then
166
+ print("图片读取成功")
167
+ -- 使用图片...
168
+ image.release(imageId)
169
+ else
170
+ print("图片读取失败")
171
+ end
172
+ ```
173
+
174
+ ### saveTo - 保存图片到指定路径。
175
+
176
+ ```lua
177
+ ---@param imageId string
178
+ ---@param filePath string
179
+ ---@return boolean
180
+ function saveTo(imageId, filePath) end
181
+ ```
182
+
183
+ **参数:**
184
+
185
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
186
+ | ---------- | ------ | -------- | ------ | -------- |
187
+ | `imageId` | string | 是 | - | 图片 ID |
188
+ | `filePath` | string | 是 | - | 保存路径 |
189
+
190
+ **返回值:**
191
+
192
+ | 类型 | 描述 |
193
+ | --------- | ------------------------------------- |
194
+ | `boolean` | `true` 表示保存成功,`false` 表示失败 |
195
+
196
+ **示例:**
197
+
198
+ ```lua
199
+ local image = require("image")
200
+ local imageId = image.captureFullScreen()
201
+ -- 获取手机文档目录
202
+ local dir = file.getInternalDir("documents")
203
+ if imageId then
204
+ image.saveTo(imageId, tostring(dir) .. "/screenshot.jpg")
205
+ image.release(imageId)
206
+ end
207
+ ```
208
+
209
+ ## 内存管理
210
+
211
+ ### release - 释放单个图片的内存。
212
+
213
+ ```lua
214
+ ---@param imageId string
215
+ function release(imageId) end
216
+ ```
217
+
218
+ **参数:**
219
+
220
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
221
+ | --------- | ------ | -------- | ------ | --------------- |
222
+ | `imageId` | string | 是 | - | 要释放的图片 ID |
223
+
224
+ ### releaseAll - 释放所有图片的内存。
225
+
226
+ ```lua
227
+ function releaseAll() end
228
+ ```
229
+
230
+ ### isRelease - 检查图片是否已被释放。
231
+
232
+ ```lua
233
+ ---@param imageId string
234
+ ---@return boolean
235
+ function isRelease(imageId) end
236
+ ```
237
+
238
+ **参数:**
239
+
240
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
241
+ | --------- | ------ | -------- | ------ | ------- |
242
+ | `imageId` | string | 是 | - | 图片 ID |
243
+
244
+ **返回值:**
245
+
246
+ | 类型 | 描述 |
247
+ | --------- | ------------------------------------- |
248
+ | `boolean` | `true` 表示已释放,`false` 表示未释放 |
249
+
250
+ **示例:**
251
+
252
+ ```lua
253
+ local image = require("image")
254
+ local imageId = image.captureFullScreen()
255
+ if imageId then
256
+ print("释放前: " .. tostring(image.isRelease(imageId))); -- false
257
+ image.release(imageId)
258
+ print("释放后: " .. tostring(image.isRelease(imageId))); -- true
259
+ end
260
+ ```
261
+
262
+ ## 图片信息
263
+
264
+ ### getSize - 获取图片尺寸。
265
+
266
+ ```lua
267
+ ---@param imageId string
268
+ ---@return any
269
+ function getSize(imageId) end
270
+ ```
271
+
272
+ **参数:**
273
+
274
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
275
+ | --------- | ------ | -------- | ------ | ------- |
276
+ | `imageId` | string | 是 | - | 图片 ID |
277
+
278
+ **返回值:**
279
+
280
+ | 类型 | 描述 |
281
+ | ---------------- | -------------------------------------------------------------- |
282
+ | `table \| nil` | 图片尺寸对象,包含 `width` 和 `height` 属性,失败时返回 `nil` |
283
+
284
+ **示例:**
285
+
286
+ ```lua
287
+ local image = require("image")
288
+ local imageId = image.captureFullScreen()
289
+ if imageId then
290
+ local size = image.getSize(imageId)
291
+ if size then
292
+ print("图片尺寸: " .. tostring(size.width) .. " x " .. tostring(size.height))
293
+ end
294
+ image.release(imageId)
295
+ end
296
+ ```
297
+
298
+ ### pixel - 获取图片指定坐标的像素颜色值。
299
+
300
+ ```lua
301
+ ---@param imageId string
302
+ ---@param x number
303
+ ---@param y number
304
+ ---@return number
305
+ function pixel(imageId, x, y) end
306
+ ```
307
+
308
+ **参数:**
309
+
310
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
311
+ | --------- | ------ | -------- | ------ | ------- |
312
+ | `imageId` | string | 是 | - | 图片 ID |
313
+ | `x` | number | 是 | - | X 坐标 |
314
+ | `y` | number | 是 | - | Y 坐标 |
315
+
316
+ **返回值:**
317
+
318
+ | 类型 | 描述 |
319
+ | -------- | -------------- |
320
+ | `number` | 颜色值(整型) |
321
+
322
+ **示例:**
323
+
324
+ ```lua
325
+ local image = require("image")
326
+ local imageId = image.captureFullScreen()
327
+ if imageId then
328
+ local color = image.pixel(imageId, 100, 100)
329
+ local colorHex = image.argb(color)
330
+ print("坐标 (100, 100) 的颜色: " .. tostring(colorHex))
331
+ image.release(imageId)
332
+ end
333
+ ```
334
+
335
+ ### argb - 将整型颜色值转换为 16 进制 RGB 字符串。
336
+
337
+ ```lua
338
+ ---@param color number
339
+ ---@return string
340
+ function argb(color) end
341
+ ```
342
+
343
+ **参数:**
344
+
345
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
346
+ | ------- | ------ | -------- | ------ | ---------- |
347
+ | `color` | number | 是 | - | 整型颜色值 |
348
+
349
+ **返回值:**
350
+
351
+ | 类型 | 描述 |
352
+ | -------- | ------------------ |
353
+ | `string` | 16 进制 RGB 字符串 |
354
+
355
+ ## 颜色识别
356
+
357
+ ### findColor - 单点找色
358
+
359
+ ```lua
360
+ ---@param imageId string
361
+ ---@param color string
362
+ ---@param threshold number
363
+ ---@param x number
364
+ ---@param y number
365
+ ---@param ex number
366
+ ---@param ey number
367
+ ---@param limit number
368
+ ---@param orz number
369
+ ---@return any
370
+ function findColor(imageId, color, threshold, x, y, ex, ey, limit, orz) end
371
+ ```
372
+
373
+ **参数:**
374
+
375
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
376
+ | ----------- | ------ | -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
377
+ | `imageId` | string | 是 | - | 图片 ID |
378
+ | `color` | string | 是 | - | 颜色值,支持 "主色-偏色" 格式,如 "#6DD1E6-#101010" |
379
+ | `threshold` | number | 是 | - | 颜色匹配阈值 (0.0-1.0) |
380
+ | `x, y` | number | 是 | - | 搜索区域左上角坐标 |
381
+ | `ex, ey` | number | 是 | - | 搜索区域右下角坐标 |
382
+ | `limit` | number | 是 | - | 最大查找数量 |
383
+ | `orz` | number | 是 | - | 查找方向(1-8) 1 左上角到右下角,纵向开始 2 左上角到右下角,横向开始 3 右上角到左下角,横向开始 4 右上角到左下角,纵向开始 5 右下角到左上角,纵向开始 6 右下角到左上角,横向开始 7 左下角到右上角,横向开始 8 左下角到右上角,纵向开始 |
384
+
385
+ **返回值:**
386
+
387
+ | 类型 | 描述 |
388
+ | ------- | ---------------------------------------------- |
389
+ | `array` | 找到的颜色点数组,每个元素包含 `x` 和 `y` 属性 |
390
+
391
+ **示例:**
392
+
393
+ ```lua
394
+ local image = require("image")
395
+ local imageId = image.captureFullScreen()
396
+ if imageId then
397
+ -- 查找蓝色按钮
398
+ local points = image.findColor(
399
+ imageId,
400
+ "#1E90FF-#101010", -- 蓝色,允许一定偏差
401
+ 0.9, -- 阈值
402
+ 0,
403
+ 0, -- 搜索区域左上角
404
+ 400,
405
+ 800, -- 搜索区域右下角
406
+ 5, -- 最多找 5 个
407
+ 1, -- 从左到右查找
408
+ )
409
+
410
+ if #points > 0 then
411
+ print("找到 " .. tostring(#points) .. " 个蓝色点")
412
+ -- 点击第一个找到的点
413
+ action.click(points[1].x, points[1].y, 100, false)
414
+ end
415
+
416
+ image.release(imageId)
417
+ end
418
+ ```
419
+
420
+ ### findMultiColor - 多点找色
421
+
422
+ ```lua
423
+ ---@param imageId string
424
+ ---@param firstColor string
425
+ ---@param threshold number
426
+ ---@param points string
427
+ ---@param x number
428
+ ---@param y number
429
+ ---@param ex number
430
+ ---@param ey number
431
+ ---@param limit number
432
+ ---@param orz number
433
+ ---@return any
434
+ function findMultiColor(imageId, firstColor, threshold, points, x, y, ex, ey, limit, orz) end
435
+ ```
436
+
437
+ **参数:**
438
+
439
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
440
+ | ------------ | ------ | -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
441
+ | `imageId` | string | 是 | - | 图片 ID |
442
+ | `firstColor` | string | 是 | - | 第一个颜色 |
443
+ | `threshold` | number | 是 | - | 颜色匹配阈值 (0.0-1.0) |
444
+ | `points` | string | 是 | - | 其他颜色点的相对位置和颜色,格式:`x1\|y1\|color1-偏色,x2\|y2\|color2-偏色` |
445
+ | `x, y` | number | 是 | - | 搜索区域左上角坐标 |
446
+ | `ex, ey` | number | 是 | - | 搜索区域右下角坐标 |
447
+ | `limit` | number | 是 | - | 最大查找数量 |
448
+ | `orz` | number | 是 | - | 查找方向(1-8) 1 左上角到右下角,纵向开始 2 左上角到右下角,横向开始 3 右上角到左下角,横向开始 4 右上角到左下角,纵向开始 5 右下角到左上角,纵向开始 6 右下角到左上角,横向开始 7 左下角到右上角,横向开始 8 左下角到右上角,纵向开始 |
449
+
450
+ **返回值:**
451
+
452
+ | 类型 | 描述 |
453
+ | ------- | ---------------------------------------------- |
454
+ | `array` | 找到的颜色点数组,每个元素包含 `x` 和 `y` 属性 |
455
+
456
+ **示例:**
457
+
458
+ ```lua
459
+ local image = require("image")
460
+ local imageId = image.captureFullScreen()
461
+ if imageId then
462
+ -- 查找特定的颜色组合(如按钮的特征颜色)
463
+ local points = image.findMultiColor(
464
+ imageId,
465
+ "#1E90FF-#101010", -- 主颜色
466
+ 0.9, -- 阈值
467
+ "10|0|#FFFFFF-#101010,20|0|#000000-#101010", -- 相对位置的其他颜色
468
+ 0,
469
+ 0,
470
+ 400,
471
+ 800,
472
+ 1,
473
+ 1,
474
+ )
475
+
476
+ if #points > 0 then
477
+ print("找到匹配的颜色组合")
478
+ action.click(points[1].x, points[1].y, 100, false)
479
+ end
480
+
481
+ image.release(imageId)
482
+ end
483
+ ```
484
+
485
+ ### countColor - 统计颜色数量
486
+
487
+ 统计指定区域内命中目标颜色的像素数量。`colors` 可以传入一个或多个候选颜色,多个颜色使用 `|` 分隔,支持 `主色-偏色` 格式,如 `#0A0A0A-#101010|#FFFFFF-#101010`。同一个像素同时命中多个候选颜色时只统计一次。
488
+
489
+ ```lua
490
+ ---@param imageId string
491
+ ---@param colors string
492
+ ---@param threshold number
493
+ ---@param x number
494
+ ---@param y number
495
+ ---@param ex number
496
+ ---@param ey number
497
+ ---@return number
498
+ function countColor(imageId, colors, threshold, x, y, ex, ey) end
499
+ ```
500
+
501
+ **参数:**
502
+
503
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
504
+ | ----------- | ------ | -------- | ------ | ------------------------------------------------------------------------------------ |
505
+ | `imageId` | string | 是 | - | 图片 ID,支持 `"screen"`、图片文件路径、HTTP 图片地址或已加载的图片 ID |
506
+ | `colors` | string | 是 | - | 颜色列表,支持 `主色-偏色\|主色-偏色` 格式,如 `#0A0A0A-#101010\|#FFFFFF-#101010` |
507
+ | `threshold` | number | 是 | - | 颜色匹配阈值 (0.0-1.0),数值越大匹配越严格 |
508
+ | `x, y` | number | 是 | - | 统计区域左上角坐标 |
509
+ | `ex, ey` | number | 是 | - | 统计区域右下角坐标;传 `0` 表示延伸到图片右侧或底部边界 |
510
+
511
+ **返回值:**
512
+
513
+ | 类型 | 描述 |
514
+ | -------- | ------------------------------------------------------------------------------------ |
515
+ | `number` | 命中目标颜色的像素数量;图片加载失败、颜色为空、颜色格式无效或区域不合法时返回 `0` |
516
+
517
+ **示例:**
518
+
519
+ ```lua
520
+ local image = require("image")
521
+ local imageId = image.captureFullScreen()
522
+ if imageId then
523
+ local count = image.countColor(
524
+ imageId,
525
+ "#0A0A0A-#101010|#FFFFFF-#101010",
526
+ 0.92,
527
+ 100,
528
+ 200,
529
+ 500,
530
+ 700,
531
+ )
532
+
533
+ print("目标区域命中颜色像素数量: " .. tostring(count))
534
+ image.release(imageId)
535
+ end
536
+ ```
537
+
538
+ ### cmpColor - 多点比色
539
+
540
+ ```lua
541
+ ---@param imageId string
542
+ ---@param points string
543
+ ---@param threshold number
544
+ ---@return boolean
545
+ function cmpColor(imageId, points, threshold) end
546
+ ```
547
+
548
+ **参数:**
549
+
550
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
551
+ | ----------- | ------ | -------- | ------ | --------------------------------------------------------------------------- |
552
+ | `imageId` | string | 是 | - | 图片 ID |
553
+ | `points` | string | 是 | - | 其他颜色点的相对位置和颜色,格式:`x1\|y1\|color1-偏色,x2\|y2\|color2-偏色` |
554
+ | `threshold` | number | 是 | - | 颜色匹配阈值 (0.0-1.0) |
555
+
556
+ **返回值:**
557
+
558
+ | 类型 | 描述 |
559
+ | --------- | ------------------------------------------- |
560
+ | `boolean` | 如果颜色匹配则返回 `true`,否则返回 `false` |
561
+
562
+ **示例:**
563
+
564
+ ```lua
565
+ local image = require("image")
566
+ local imageId = image.captureFullScreen()
567
+ if imageId then
568
+ -- 检查特定区域是否为预期颜色
569
+ local isMatch = image.cmpColor(
570
+ imageId,
571
+ "1|2|#6DD1E6-#101010",
572
+ 0.9, -- 阈值
573
+ )
574
+
575
+ if isMatch then
576
+ print("颜色匹配")
577
+ end
578
+
579
+ image.release(imageId)
580
+ end
581
+ ```
582
+
583
+ ## 图像识别
584
+
585
+ ### findImage - 找图
586
+
587
+ 在大图(通常是屏幕截图)中查找小图(模板)。支持多种匹配算法,可按 `|` 同时传入多个模板。
588
+
589
+ ```lua
590
+ ---@param imageId string
591
+ ---@param templateImageId string
592
+ ---@param x number
593
+ ---@param y number
594
+ ---@param ex number
595
+ ---@param ey number
596
+ ---@param threshold number
597
+ ---@param limit number
598
+ ---@param method number
599
+ ---@param rgb boolean?
600
+ ---@param options table?
601
+ ---@return any
602
+ function findImage(imageId, templateImageId, x, y, ex, ey, threshold, limit, method, rgb, options) end
603
+ ```
604
+
605
+ **参数:**
606
+
607
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
608
+ | ---------------------- | --------- | -------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
609
+ | `imageId` | string | 是 | - | `"screen"`-当前屏幕截图, `string`-图片文件路径或 URL ,`imageId`-图片 ID(通过 image 模块获取) |
610
+ | `templateImageId` | string | 是 | - | `"screen"`-当前屏幕截图, `string`-图片文件路径或 URL ,`imageId`-图片 ID(通过 image 模块获取)支持按\|分割,多个图片按顺序查找 |
611
+ | `x, y` | number | 是 | - | 搜索区域左上角坐标 |
612
+ | `ex, ey` | number | 是 | - | 搜索区域右下角坐标;传 `0` 表示延伸到图片右侧或底部边界 |
613
+ | `threshold` | number | 是 | - | 匹配阈值 (0.0-1.0)。method `0`/`99` 建议 `0.5`–`0.6`;普通模板匹配(`1`/`3`/`5`)建议 `0.9`–`0.995` |
614
+ | `limit` | number | 是 | - | 最大查找数量,每个模板图片最多找 limit 个匹配结果 |
615
+ | `method` | number | 是 | - | 匹配方法,见下方说明 |
616
+ | `rgb` | boolean | 否 | `false` | 是否使用 RGB 找图,默认 `false` 会自动转灰度找图 |
617
+ | `options` | table | 否 | - | 额外选项,目前仅 method=`99` 时生效 |
618
+ | `options.scaleFactors` | number\[] | 否 | `[1.0, 0.9, 1.1, 0.8, 1.2]` | 仅 method=`99` 生效。模板相对当前图的缩放比列表(**不是** `device.getScreenScale()`)。应按 baseScale 动态计算,见下方详解;默认值只适合尺寸接近时的盲扫 |
619
+
620
+ #### method 匹配方法说明
621
+
622
+ | method | 名称 | 原理简述 | 适用场景 | 速度 |
623
+ | ------ | ---------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------ | -------- |
624
+ | `5` | TM_CCOEFF_NORMED | 标准模板匹配(归一化相关系数),模板必须与目标**像素尺寸一致** | 同分辨率、同尺寸截图模板,最常用 | 快 |
625
+ | `3` | TM_CCORR_NORMED | 标准模板匹配(归一化相关) | 同尺寸模板;PNG 透明模板带 mask 时内部会优先用它 | 快 |
626
+ | `1` | TM_SQDIFF_NORMED | 标准模板匹配(归一化平方差),分数越小越像,引擎已换算为越大越像 | 同尺寸模板 | 快 |
627
+ | `0` | SIFT 全分辨率 | 提取 SIFT 特征点做匹配,对旋转、轻微形变更鲁棒,不要求模板与目标同尺寸 | 目标可能旋转/形变,或跨分辨率找图 | 较慢 |
628
+ | `99` | 全分辨率缩放匹配法 | 把**模板**按多个比例缩放后,再做 `TM_CCOEFF_NORMED` 模板匹配(有透明通道时用 `TM_CCORR_NORMED`) | 目标与模板尺寸不完全一致,但形状相同 | 中等偏慢 |
629
+
630
+ #### 什么是「缩放」全分辨率找图(method = 99)
631
+
632
+ 这里的「缩放」**不是**把屏幕截图缩小,也**不是**设备显示缩放(`device.getScreenScale()`),而是:
633
+
634
+ > 在匹配前,把**模板小图**按 `scaleFactors` 里的比例逐个放大/缩小,再与**原尺寸**搜索区域做模板匹配。
635
+
636
+ - `factor = 1.0`:模板保持原像素尺寸去匹配
637
+ - `factor < 1.0`:先把模板缩小再匹配(当前屏幕上的目标比模板更小)
638
+ - `factor > 1.0`:先把模板放大再匹配(当前屏幕上的目标比模板更大)
639
+
640
+ 引擎内部是 `Imgproc.resize(template, fx=factor, fy=factor)`,**横向、纵向使用同一个比例**(等比缩放)。
641
+ 返回结果里的 `width` / `height` 是缩放后的模板尺寸,`scaleX` / `scaleY` 是本次命中用到的比例。
642
+
643
+ 工作流程:
644
+
645
+ 1. 读取搜索区域(大图)和模板(小图),默认转灰度(`rgb=true` 时保留彩色)。
646
+ 2. 按 `scaleFactors` **数组顺序**,对模板执行等比缩放。
647
+ 3. 若缩放后的模板比搜索区域还大,跳过该比例。
648
+ 4. 用缩放后的模板做 `TM_CCOEFF_NORMED` 匹配(透明 PNG 用 `TM_CCORR_NORMED` + alpha mask)。
649
+ 5. 收集 `confidence >= threshold` 的命中;重叠区域去重,保留置信度更高者。
650
+ 6. 找满 `limit` 个后提前结束——所以**更可能命中的比例要放前面**。
651
+
652
+ #### 如何选择 `scaleFactors`(重点)
653
+
654
+ `scaleFactors` 不是随便填几个小数,而是回答这个问题:
655
+
656
+ > 「模板图里的目标,到当前屏幕上会变成原来的几倍宽/高?」
657
+
658
+ ##### 1. 先算「目标比例」baseScale
659
+
660
+ UI 随分辨率等比变化时(大多数 App / 游戏界面):
661
+
662
+ ```text
663
+ baseScale = 当前设备逻辑宽 / 截取模板时设备的逻辑宽
664
+ ```
665
+
666
+ 也可用高:
667
+
668
+ ```text
669
+ baseScale = 当前设备逻辑高 / 截取模板时设备的逻辑高
670
+ ```
671
+
672
+ 宽高比一致时两者相同;不一致时优先用**与布局更相关的那条边**(竖屏 App 常用高,横屏游戏常用宽),或取两者平均。
673
+
674
+ 这里的「逻辑宽高」请用找图坐标系对应的尺寸,一般是 `device.getScreenRealSize()`(实际像素分辨率)。
675
+ **不要**把 `device.getScreenScale()`(屏幕 scale 因子)直接当成 `scaleFactors` 里的值——两者不是一回事。
676
+
677
+ 若你确切知道模板像素尺寸和屏幕上目标像素尺寸,也可以直接:
678
+
679
+ ```text
680
+ baseScale = 屏幕上目标宽度(px) / 模板宽度(px)
681
+ // 或
682
+ baseScale = 屏幕上目标高度(px) / 模板高度(px)
683
+ ```
684
+
685
+ **数值例子:**
686
+
687
+ | 截模板设备 | 当前运行设备 | 计算 | baseScale |
688
+ | -------------- | -------------- | ---------------------------- | --------- |
689
+ | iPhone 8 750px | 同机 | 750 / 750 | `1.0` |
690
+ | 750 宽 | 1170 宽 | 1170 / 750 | `1.56` |
691
+ | 1170 宽 | 750 宽 | 750 / 1170 | `0.641` |
692
+ | 1080 宽安卓 | 1440 宽安卓 | 1440 / 1080 | `1.333` |
693
+ | 模板按钮 120px | 屏上按钮 96px | 96 / 120 | `0.8` |
694
+
695
+ 含义对照:
696
+
697
+ | baseScale | 含义 | 引擎会对模板做什么 |
698
+ | --------- | ------------------------------------------ | ----------------------- |
699
+ | `1.0` | 当前目标与模板同尺寸 | 不缩放 |
700
+ | `0.64` | 当前目标大约是模板的 64%(高分屏模板跑低分) | 缩到 64% 再匹配 |
701
+ | `1.56` | 当前目标大约是模板的 156%(低分屏模板跑高分) | 放大到 156% 再匹配 |
702
+
703
+ ##### 2. 再围绕 baseScale 生成搜索列表
704
+
705
+ 真实设备上还会有状态栏、安全区、App 缩放、截图工具裁切误差等,baseScale 很少绝对精确,所以要在 baseScale **附近扫一小段**:
706
+
707
+ ```text
708
+ scaleFactors ≈ [ baseScale,
709
+ baseScale ± step,
710
+ baseScale ± 2*step,
711
+ ... ]
712
+ ```
713
+
714
+ 推荐参数:
715
+
716
+ | 项目 | 建议 | 原因 |
717
+ | -------------- | ----------------------------------------- | ---- |
718
+ | 中心值 | 算出来的 `baseScale` | 最可能命中,必须放第一位 |
719
+ | 步进 `step` | `0.05`~`0.1` | 太疏容易跳过真实尺寸;太密浪费时间 |
720
+ | 半宽度 | `±0.1`~`±0.2`(约 ±10%~20%) | 覆盖状态栏/安全区/轻微布局差 |
721
+ | 总档数 | 3~7 个 | 每多一档就多跑一轮全图模板匹配 |
722
+ | 阈值 threshold | `0.5`~`0.6` 起调 | 缩放插值会降低相关分数,别用 0.9+ |
723
+ | 顺序 | **baseScale 最先**,再左右交替扩开 | 找满 limit 会提前结束 |
724
+
725
+ 生成示例(伪代码思路):
726
+
727
+ ```lua
728
+ -- 截模板时的设备宽(写进脚本配置,或写在模板文件名里)
729
+ local templateDeviceWidth = 750
730
+ -- 当前设备实际宽
731
+ local currentWidth = device.getScreenRealSize().width
732
+ local baseScale = currentWidth / templateDeviceWidth
733
+ -- 围绕 baseScale,步进 0.05,左右各扩 2 档 → 共 5 个
734
+ local function buildScaleFactors(base, step = 0.05, halfRange = 2)
735
+ local list = [Number(base.toFixed(4))]
736
+ for i = 1, halfRange do
737
+ list.push(Number((base - step * i).toFixed(4)))
738
+ list.push(Number((base + step * i).toFixed(4)))
739
+ end
740
+ -- 过滤掉无意义的比例
741
+ return list.filter((s) => s > 0.05 and s < 8)
742
+ end
743
+
744
+ local scaleFactors = buildScaleFactors(baseScale)
745
+ -- 例如 baseScale=1.56, step=0.05, halfRange=2
746
+ -- → [1.56, 1.51, 1.61, 1.46, 1.66]
747
+ ```
748
+
749
+ ##### 3. 按场景怎么选
750
+
751
+ | 场景 | 怎么设 `scaleFactors` | threshold |
752
+ | ---- | --------------------- | --------- |
753
+ | 模板就是本机截的,尺寸确定一致 | 不必用 99,直接 method `5`;若坚持用 99 则 `[1.0]` | `0.9+` / `0.55` |
754
+ | 已知截图机型与当前机型分辨率 | 算 `baseScale`,再 `±0.05`~`±0.1` 扩 3~5 档 | `0.5`~`0.6` |
755
+ | 多机型跑同一套模板,分辨率跨度大 | 按每台设备运行时动态算 baseScale,不要写死默认那组 | `0.5`~`0.6` |
756
+ | 完全不知道模板来源分辨率 | 先用 method `0`(SIFT);或宽范围粗扫(慢,如 0.5~2.0 步进 0.1) | `0.5` 左右 |
757
+ | 只要微调(系统字体/显示缩放导致差几像素) | `[1.0, 0.95, 1.05, 0.9, 1.1]` | `0.55`~`0.65` |
758
+ | 横竖屏切换 / 目标会旋转 | method `99` **不够**,改用 method `0` SIFT | `0.5`~`0.6` |
759
+
760
+ 默认值 `[1.0, 0.9, 1.1, 0.8, 1.2]` 的定位:
761
+
762
+ - 假设「模板大致接近当前尺寸」,在 80%~120% 之间盲扫
763
+ - **只适合尺寸差不大的兜底**,不适合 750 ↔ 1170 这种跨度(baseScale≈1.56,默认列表根本扫不到)
764
+ - 生产脚本应**按设备算 baseScale**,不要依赖这组默认值硬扛跨分辨率
765
+
766
+ ##### 4. 常见误区
767
+
768
+ 1. **把 `device.getScreenScale()` 填进 scaleFactors**
769
+ `getScreenScale()` 是屏幕 scale(如 2x/3x 显示倍率),不是「模板相对当前图」的缩放比。
770
+
771
+ 2. **跨大分辨率仍用默认 `[1.0, 0.9, 1.1, 0.8, 1.2]`**
772
+ 真实 baseScale 在 1.5 时,默认列表全军覆没。
773
+
774
+ 3. **threshold 仍用 0.9**
775
+ resize 插值会损失细节,method `99` 相关分通常明显低于同尺寸 method `5`,建议从 `0.55` 左右调。
776
+
777
+ 4. **档位又多又密**
778
+ 全屏 × 10 个 factor ≈ 10 次模板匹配,卡顿明显。先算准 baseScale,再小范围扩。
779
+
780
+ 5. **模板含大量透明/JPEG 压缩噪点**
781
+ 缩放后更易误匹配;优先 PNG 透明模板,并尽量裁紧目标外轮廓。
782
+
783
+ 6. **搜索区域小于放大后的模板**
784
+ 该 factor 会被跳过。放大场景请保证 ROI 足够大,或全屏搜。
785
+
786
+ ##### 5. 与 method `0`(SIFT)怎么选
787
+
788
+ | | method `99` 缩放匹配 | method `0` SIFT |
789
+ | -------------- | ---------------------------------- | ---------------------------------- |
790
+ | 尺寸变化 | 支持(靠你提供的比例穷举) | 支持(特征点,不靠固定比例) |
791
+ | 你需要知道比例 | 最好先算 baseScale | 不需要 |
792
+ | 旋转 / 形变 | 基本不支持 | 较鲁棒 |
793
+ | 阈值建议 | `0.5`–`0.6` | `0.5`–`0.6` |
794
+ | 透明 PNG 模板 | 支持(alpha 作权重 mask) | 支持(alpha 作特征掩码) |
795
+ | 性能 | 与 factor 数量近似成正比,通常更快 | 特征提取重,通常更慢 |
796
+ | 推荐 | 比例可估算的跨分辨率找图 | 比例未知、或有旋转/透视时 |
797
+
798
+ **返回值:**
799
+
800
+ | 类型 | 描述 |
801
+ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
802
+ | `array` | 匹配结果数组。`index` 为模板在 `templateImageId` 中的索引(从 0 开始)。method=`99` 时额外包含 `scaleX`、`scaleY`(本次命中使用的缩放比) |
803
+
804
+ **示例:**
805
+
806
+ ```lua
807
+ local image = require("image")
808
+ -- 1) 同分辨率标准找图(最常用,模板就是本机截的)
809
+ local matches = image.findImage(
810
+ "screen",
811
+ "template.jpg|template2.jpg",
812
+ 0,
813
+ 0,
814
+ 400,
815
+ 800,
816
+ 0.9,
817
+ 3,
818
+ 5, -- TM_CCOEFF_NORMED
819
+ false,
820
+ )
821
+
822
+ if #matches > 0 then
823
+ local best = matches[1]
824
+ print("找到匹配,置信度: " .. tostring(best.confidence))
825
+ action.click(best.centerX, best.centerY, 100, false)
826
+ end
827
+ -- 2) 缩放全分辨率找图:按「截模板设备宽 / 当前设备宽」计算比例
828
+ -- 假设模板是在宽度 750 的设备上截的
829
+ local templateDeviceWidth = 750
830
+ local currentWidth = device.getScreenRealSize().width
831
+ local baseScale = currentWidth / templateDeviceWidth
832
+
833
+ local function buildScaleFactors(base, step = 0.05, halfRange = 2)
834
+ local list = [Number(base.toFixed(4))]
835
+ for i = 1, halfRange do
836
+ list.push(Number((base - step * i).toFixed(4)))
837
+ list.push(Number((base + step * i).toFixed(4)))
838
+ end
839
+ return list.filter((s) => s > 0.05 and s < 8)
840
+ end
841
+
842
+ local scaleFactors = buildScaleFactors(baseScale)
843
+ -- 750 → 1170 时约等于 [1.56, 1.51, 1.61, 1.46, 1.66]
844
+ print("baseScale=" .. tostring(baseScale.toFixed(3)) .. " scaleFactors=" .. tostring(ToJsonString(scaleFactors)))
845
+
846
+ local scaled = image.findImage(
847
+ "screen",
848
+ "btn_start.png",
849
+ 0,
850
+ 0,
851
+ 0,
852
+ 0, -- 全屏;放大模板时 ROI 太小会被跳过
853
+ 0.55, -- 多尺度建议 0.5-0.6,不要用 0.9
854
+ 1,
855
+ 99,
856
+ false,
857
+ { scaleFactors },
858
+ )
859
+
860
+ if #scaled > 0 then
861
+ local hit = scaled[1]
862
+ print(
863
+ "命中 scale=" .. tostring(hit.scaleX) .. " 尺寸=" .. tostring(hit.width) .. "x" .. tostring(hit.height) .. " 置信度=" .. tostring(hit.confidence),
864
+ )
865
+ action.click(hit.centerX, hit.centerY, 100, false)
866
+ end
867
+ -- 3) 已知模板宽和屏幕目标大概宽时,直接用像素比
868
+ -- local baseScale = expectedTargetWidthPx / templateWidthPx
869
+ ```
870
+
871
+ ## 图像处理
872
+
873
+ ### clip - 裁剪图片。
874
+
875
+ ```lua
876
+ ---@param imageId string
877
+ ---@param x number
878
+ ---@param y number
879
+ ---@param ex number
880
+ ---@param ey number
881
+ ---@return string
882
+ function clip(imageId, x, y, ex, ey) end
883
+ ```
884
+
885
+ **参数:**
886
+
887
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
888
+ | --------- | ------ | -------- | ------ | ------------------ |
889
+ | `imageId` | string | 是 | - | 原图片 ID |
890
+ | `x, y` | number | 是 | - | 裁剪区域左上角坐标 |
891
+ | `ex, ey` | number | 是 | - | 裁剪区域右下角坐标 |
892
+
893
+ **返回值:**
894
+
895
+ | 类型 | 描述 |
896
+ | -------- | ----------------- |
897
+ | `string` | 裁剪后的新图片 ID |
898
+
899
+ **示例:**
900
+
901
+ ```lua
902
+ local image = require("image")
903
+ local imageId = image.captureFullScreen()
904
+ -- 获取手机文档目录
905
+ local dir = file.getInternalDir("documents")
906
+ if imageId then
907
+ -- 裁剪屏幕上半部分
908
+ local screen = device.getScreenRealSize()
909
+ local clippedId = image.clip(imageId, 0, 0, screen.width, screen.height / 2)
910
+
911
+ if clippedId then
912
+ image.saveTo(clippedId, tostring(dir) .. "/top_half.jpg")
913
+ image.release(clippedId)
914
+ end
915
+
916
+ image.release(imageId)
917
+ end
918
+ ```
919
+
920
+ ### rotateImage - 旋转图片。
921
+
922
+ ```lua
923
+ ---@param imageId string
924
+ ---@param degree number
925
+ ---@return string | nil
926
+ function rotateImage(imageId, degree) end
927
+ ```
928
+
929
+ **参数:**
930
+
931
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
932
+ | --------- | ------ | -------- | ------ | ----------------------------- |
933
+ | `imageId` | string | 是 | - | 原图片 ID |
934
+ | `degree` | number | 是 | - | 旋转角度,只能是 90、-90、180 |
935
+
936
+ **返回值:**
937
+
938
+ | 类型 | 描述 |
939
+ | ---------------- | ----------------------------------- |
940
+ | `string \| nil` | 旋转后的新图片 ID 失败时返回 `nil` |
941
+
942
+ **示例:**
943
+
944
+ ```lua
945
+ local image = require("image")
946
+ local imageId = image.readImage("photo.jpg")
947
+ -- 获取手机文档目录
948
+ local dir = file.getInternalDir("documents")
949
+ if imageId then
950
+ local rotatedId = image.rotateImage(imageId, 90)
951
+ if rotatedId then
952
+ image.saveTo(rotatedId, tostring(dir) .. "/photo_rotated.jpg")
953
+ image.release(rotatedId)
954
+ end
955
+ image.release(imageId)
956
+ end
957
+ ```
958
+
959
+ ### gray - 将图片转换为灰度图。
960
+
961
+ ```lua
962
+ ---@param imageId string
963
+ ---@return string
964
+ function gray(imageId) end
965
+ ```
966
+
967
+ **参数:**
968
+
969
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
970
+ | --------- | ------ | -------- | ------ | --------- |
971
+ | `imageId` | string | 是 | - | 原图片 ID |
972
+
973
+ **返回值:**
974
+
975
+ | 类型 | 描述 |
976
+ | -------- | ------------------- |
977
+ | `string` | 灰度化后的新图片 ID |
978
+
979
+ **示例:**
980
+
981
+ ```lua
982
+ local image = require("image")
983
+ local imageId = image.captureFullScreen()
984
+ -- 获取手机文档目录
985
+ local dir = file.getInternalDir("documents")
986
+ if imageId then
987
+ local grayId = image.gray(imageId)
988
+ image.saveTo(grayId, tostring(dir) .. "/screenshot_gray.jpg")
989
+ image.release(grayId)
990
+ image.release(imageId)
991
+ end
992
+ ```
993
+
994
+ ### binaryzation - 将图片进行二值化处理。
995
+
996
+ ```lua
997
+ ---@param imageId string
998
+ ---@param threshold number
999
+ ---@return string
1000
+ function binaryzation(imageId, threshold) end
1001
+ ```
1002
+
1003
+ **参数:**
1004
+
1005
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
1006
+ | ----------- | ------ | -------- | ------ | ---------------------- |
1007
+ | `imageId` | string | 是 | - | 原图片 ID |
1008
+ | `threshold` | number | 是 | - | 二值化阈值 (0.0-255.0) |
1009
+
1010
+ **返回值:**
1011
+
1012
+ | 类型 | 描述 |
1013
+ | -------- | ------------------- |
1014
+ | `string` | 二值化后的新图片 ID |
1015
+
1016
+ **示例:**
1017
+
1018
+ ```lua
1019
+ local image = require("image")
1020
+ local imageId = image.captureFullScreen()
1021
+ -- 获取手机文档目录
1022
+ local dir = file.getInternalDir("documents")
1023
+ if imageId then
1024
+ local binaryId = image.binaryzation(imageId, 128)
1025
+ image.saveTo(binaryId, tostring(dir) .. "/screenshot_binary.jpg")
1026
+ image.release(binaryId)
1027
+ image.release(imageId)
1028
+ end
1029
+ ```
1030
+
1031
+ ### drawRect - 绘制矩形。
1032
+
1033
+ ```lua
1034
+ ---@param imageId string
1035
+ ---@param x number
1036
+ ---@param y number
1037
+ ---@param ex number
1038
+ ---@param ey number
1039
+ ---@param color string
1040
+ ---@param thickness number
1041
+ function drawRect(imageId, x, y, ex, ey, color, thickness) end
1042
+ ```
1043
+
1044
+ **参数:**
1045
+
1046
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
1047
+ | ----------- | ------ | -------- | ------ | --------------------------- |
1048
+ | `imageId` | string | 是 | - | 原图片 ID |
1049
+ | `x, y` | number | 是 | - | 矩形左上角坐标 |
1050
+ | `ex, ey` | number | 是 | - | 矩形右下角坐标 |
1051
+ | `color` | string | 是 | - | 颜色,如 "#FF0000" 表示红色 |
1052
+ | `thickness` | number | 是 | - | 线宽 |
1053
+
1054
+ **示例:**
1055
+
1056
+ ```lua
1057
+ local image = require("image")
1058
+ -- 获取手机文档目录
1059
+ local dir = file.getInternalDir("documents")
1060
+
1061
+ local imageId = image.captureFullScreen()
1062
+ if imageId then
1063
+ image.drawRect(imageId, 100, 100, 200, 100, "#FF0000", 2)
1064
+ image.saveTo(imageId, tostring(dir) .. "/test.jpg")
1065
+ image.release(imageId)
1066
+ end
1067
+ ```
1068
+
1069
+ ### scanCode - 扫码条码(支持一维码和二维码)
1070
+
1071
+ ```lua
1072
+ ---@param imageId string
1073
+ ---@return string | nil
1074
+ function scanCode(imageId) end
1075
+ ```
1076
+
1077
+ **参数:**
1078
+
1079
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
1080
+ | --------- | ------ | -------- | ------ | --------- |
1081
+ | `imageId` | string | 是 | - | 原图片 ID |
1082
+
1083
+ **返回值:**
1084
+
1085
+ | 类型 | 描述 |
1086
+ | ---------------- | --------------------------- |
1087
+ | `string \| nil` | 扫码结果,失败时返回 `nil` |
1088
+
1089
+ **示例:**
1090
+
1091
+ ```lua
1092
+ local image = require("image")
1093
+ local imageId = image.captureFullScreen()
1094
+ if imageId then
1095
+ local result = image.scanCode(imageId)
1096
+ if result then
1097
+ print("扫码结果: " .. tostring(result))
1098
+ else
1099
+ print("扫码失败")
1100
+ end
1101
+ image.release(imageId)
1102
+ end
1103
+ ```
1104
+
1105
+ ## Base64 转换
1106
+
1107
+ ### base64ToImage - 将 Base64 字符串转换为图片。
1108
+
1109
+ ```lua
1110
+ ---@param base64 string
1111
+ ---@return string
1112
+ function base64ToImage(base64) end
1113
+ ```
1114
+
1115
+ **参数:**
1116
+
1117
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
1118
+ | -------- | ------ | -------- | ------ | ------------- |
1119
+ | `base64` | string | 是 | - | Base64 字符串 |
1120
+
1121
+ **返回值:**
1122
+
1123
+ | 类型 | 描述 |
1124
+ | -------- | --------------- |
1125
+ | `string` | 转换后的图片 ID |
1126
+
1127
+ **示例:**
1128
+
1129
+ ```lua
1130
+ local image = require("image")
1131
+ local base64Data =
1132
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg=="
1133
+ local imageId = image.base64ToImage(base64Data)
1134
+ -- 获取手机文档目录
1135
+ local dir = file.getInternalDir("documents")
1136
+ if imageId then
1137
+ image.saveTo(imageId, tostring(dir) .. "/base64.jpg")
1138
+ image.release(imageId)
1139
+ end
1140
+ ```
1141
+
1142
+ ### toBase64Format - 将图片转换为 Base64 字符串。
1143
+
1144
+ ```lua
1145
+ ---@param imageId string
1146
+ ---@param format string
1147
+ ---@param q number
1148
+ ---@return string
1149
+ function toBase64Format(imageId, format, q) end
1150
+ ```
1151
+
1152
+ **参数:**
1153
+
1154
+ | 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
1155
+ | --------- | ------ | -------- | ------ | ------------------------------ |
1156
+ | `imageId` | string | 是 | - | 原图片 ID |
1157
+ | `format` | string | 是 | - | 图片格式(如 "jpg", "png") |
1158
+ | `q` | number | 是 | - | 质量 (1-100),数字越大质量越高 |
1159
+
1160
+ **返回值:**
1161
+
1162
+ | 类型 | 描述 |
1163
+ | -------- | ---------------------- |
1164
+ | `string` | 转换后的 Base64 字符串 |
1165
+
1166
+ **示例:**
1167
+
1168
+ ```lua
1169
+ local image = require("image")
1170
+ local imageId = image.captureFullScreen()
1171
+ if imageId then
1172
+ local base64 = image.toBase64Format(imageId, "jpg", 90)
1173
+ print("Base64 数据: " .. tostring(base64.substring(0, 100)) .. "...")
1174
+ image.release(imageId)
1175
+ end
1176
+ ```
1177
+