diff --git a/components/apex-camera/apex-camera copy.uvue b/components/apex-camera/apex-camera copy.uvue new file mode 100644 index 0000000..5f39bae --- /dev/null +++ b/components/apex-camera/apex-camera copy.uvue @@ -0,0 +1,640 @@ + + + + + diff --git a/components/apex-camera/apex-camera.uvue b/components/apex-camera/apex-camera.uvue new file mode 100644 index 0000000..8d44570 --- /dev/null +++ b/components/apex-camera/apex-camera.uvue @@ -0,0 +1,594 @@ + + + + + diff --git a/components/apex-camera/index.uts b/components/apex-camera/index.uts new file mode 100644 index 0000000..a11957d --- /dev/null +++ b/components/apex-camera/index.uts @@ -0,0 +1 @@ +export * from './type.uts' diff --git a/components/apex-camera/type.uts b/components/apex-camera/type.uts new file mode 100644 index 0000000..f435a26 --- /dev/null +++ b/components/apex-camera/type.uts @@ -0,0 +1,29 @@ +export type ApexCameraMode = 'photo' | 'video' +export type ApexCameraPosition = 'front' | 'back' +export type ApexCameraFlashMode = 'off' | 'on' | 'auto' + +export type ApexCameraPhotoResult = { + path : string + width : number + height : number + savedToAlbum : boolean +} + +export type ApexCameraVideoResult = { + path : string + duration : number + size : number + savedToAlbum : boolean +} + +export type ApexCameraProps = { + title : string + subTitle : string + tipLines : string[] + autoInit : boolean + autoBack : boolean + maxDuration : number + defaultPosition : ApexCameraPosition + defaultFlashMode : ApexCameraFlashMode + defaultSaveToAlbum : boolean +} diff --git a/components/使用说明.md b/components/使用说明.md new file mode 100644 index 0000000..8cc77e7 --- /dev/null +++ b/components/使用说明.md @@ -0,0 +1,287 @@ +# apex-camera 相机组件使用文档 + +## 概述 + +`apex-camera` 是一个基于 UTS 的跨平台相机组件,支持 **Android**、**iOS** 和**鸿蒙**三端。组件封装了拍照、录像、闪光灯控制、前后摄像头切换、保存到相册等常见相机功能,开箱即用。 + +## 文件结构 + +``` +components/apex-camera/ +├── apex-camera.uvue # 简洁版风格(带照片遮罩层) +├── apex-camera copy.uvue # 完整版风格(带顶栏、状态面板、工具面板) +├── index.uts # 导出入口 +└── type.uts # 类型定义 +``` + +> 两个 `.uvue` 文件提供了不同的 UI 风格,功能逻辑完全一致。可按需选用其中一个。 + +## 类型定义 + +### ApexCameraProps(组件 Props) + +```ts +type ApexCameraProps = { + title: string // 标题文本,默认 "UTS 相机组件" + subTitle: string // 副标题/提示文本,默认 "支持 Android + iOS + 鸿蒙" + tipLines: string[] // 提示信息行 + autoInit: boolean // 是否自动初始化相机,默认 true + autoBack: boolean // 点击返回时是否自动返回上一页,默认 true + maxDuration: number // 最大录像时长(秒),默认 60 + defaultPosition: 'front' | 'back' // 默认摄像头方向,默认 'back' + defaultFlashMode: 'off' | 'on' | 'auto' // 默认闪光灯模式,默认 'off' + defaultSaveToAlbum: boolean // 默认是否保存到相册,默认 false +} +``` + +### ApexCameraPhotoResult(拍照结果) + +```ts +type ApexCameraPhotoResult = { + path: string // 照片临时路径 + width: number // 照片宽度 + height: number // 照片高度 + savedToAlbum: boolean // 是否已保存到系统相册 +} +``` + +### ApexCameraVideoResult(录像结果) + +```ts +type ApexCameraVideoResult = { + path: string // 视频临时路径 + duration: number // 视频时长 + size: number // 视频文件大小 + savedToAlbum: boolean // 是否已保存到系统相册 +} +``` + +## Props(属性) + +| 属性名 | 类型 | 默认值 | 说明 | +|--------|------|--------|------| +| `title` | `string` | `"UTS 相机组件"` | 顶栏标题(仅完整版) | +| `subTitle` | `string` | `"支持 Android + iOS + 鸿蒙"` | 初始化遮罩层的主提示文字 | +| `tipLines` | `string[]` | `[]` | 额外的提示信息行 | +| `autoInit` | `boolean` | `true` | 是否在 `onMounted` 时自动启动相机 | +| `autoBack` | `boolean` | `true` | 点击返回按钮是否自动 `navigateBack` | +| `maxDuration` | `number` | `60` | 录像最大时长(秒) | +| `defaultPosition` | `'front' \| 'back'` | `'back'` | 默认摄像头朝向 | +| `defaultFlashMode` | `'off' \| 'on' \| 'auto'` | `'off'` | 默认闪光灯模式 | +| `defaultSaveToAlbum` | `boolean` | `false` | 默认是否将结果保存到系统相册 | + +## Events(事件) + +| 事件名 | 参数类型 | 说明 | +|--------|----------|------| +| `ready` | 无 | 相机初始化完成 | +| `photo` | `ApexCameraPhotoResult` | 拍照完成 | +| `video` | `ApexCameraVideoResult` | 录像完成 | +| `error` | `message: string` | 发生错误(含错误信息) | + +## Exposed Methods(暴露方法) + +组件通过 `defineExpose` 暴露以下方法,父组件可通过 ref 调用: + +| 方法名 | 签名 | 说明 | +|--------|------|------| +| `bootCamera` | `() => Promise` | 手动启动/重启相机 | +| `takePhoto` | `() => void` | 触发拍照 | +| `recordVideo` | `() => void` | 触发录像(再次调用停止) | +| `toggleCamera` | `() => Promise` | 切换前后摄像头 | +| `changeFlashMode` | `(mode: 'off' \| 'on' \| 'auto') => void` | 设置闪光灯模式 | +| `cycleFlashMode` | `() => void` | 循环切换闪光灯模式(off→auto→on→off) | + +> 注意:`cycleFlashMode` 仅在简洁版(`apex-camera.uvue`)中暴露。 + +## 基本用法 + +### 1. 引入组件 + +在 `pages.json` 中注册组件: + +```json +{ + "easycom": { + "autoscan": true + } +} +``` + +或者直接 import: + +```vue + +``` + +### 2. 最简单的使用 + +```vue + + + +``` + +### 3. 完整配置示例 + +```vue + + + +``` + +## 两种 UI 风格对比 + +### 简洁版(`apex-camera.uvue`) + +- 全屏预览 + 照片遮罩层(可自定义遮罩图) +- 底部一栏:缩略图 + 拍照按钮 + 切换摄像头 +- 左上角闪光灯切换按钮 +- 适合需要自定义遮罩/引导框的场景 + +### 完整版(`apex-camera copy.uvue`) + +- 顶部导航栏:返回按钮 + 标题 + 状态徽章 +- 全屏预览 + 初始化遮罩 +- 状态面板:显示摄像头方向、闪光灯、保存状态等 +- 底部操作栏:切换 + 拍照 + 录像 + 状态文本 +- 底部工具面板:保存到相册开关 + 闪光灯三态切换 +- 适合需要完整调试信息和状态展示的场景 + +## 注意事项 + +1. **相机权限**:使用前请确保已在各平台配置相机权限。Android 需在 `AndroidManifest.xml` 中声明,iOS 需在 `Info.plist` 中添加 `NSCameraUsageDescription`。 +2. **相册保存**:如需保存到系统相册,Android 还需 `WRITE_EXTERNAL_STORAGE` 权限,iOS 需 `NSPhotoLibraryAddUsageDescription`。 +3. **临时文件**:拍照/录像返回的路径为临时文件路径,如需持久保存需自行移动或上传。 +4. **录像限制**:通过 `maxDuration` 控制最大录像时长,超出后会自动停止。 +5. **组件引用**:通过 `easycom` 自动扫描引入即可,无需手动 import。 + +```vue + + + + + + +``` \ No newline at end of file diff --git a/gittest.txt b/gittest.txt deleted file mode 100644 index 02071b1..0000000 --- a/gittest.txt +++ /dev/null @@ -1 +0,0 @@ -提交下git,描述为 调整相机前指定备份 diff --git a/manifest.json b/manifest.json index f1695ea..2bd21c5 100644 --- a/manifest.json +++ b/manifest.json @@ -40,7 +40,10 @@ "", "", "", - "" + "", + "", + "", + "" ] }, /* ios打包配置 */ diff --git a/package.json b/package.json index 8eba4af..34a56ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,29 @@ { - "dependencies": { - "blueimp-md5": "^2.19.0", - "js-sha256": "^0.11.1" - } + "id": "apex-gu-cheng-uts", + "name": "安卓鸿蒙IOS调用相机摄像头", + "displayName": "安卓鸿蒙IOS调用相机摄像头", + "version": "1.0.0", + "description": "可以在APP中实时显示摄像头预览画面,同时进行拍照录像等功能;", + "keywords": [ + "鸿蒙", + "安卓", + "IOS", + "摄像头", + "相机" + ], + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + } + }, + "uni_modules": { + "dependencies": [], + "encrypt": [] + } } \ No newline at end of file diff --git a/pages/upload/camera_capture.nvue b/pages/upload/camera_capture.nvue new file mode 100644 index 0000000..0f10e1a --- /dev/null +++ b/pages/upload/camera_capture.nvue @@ -0,0 +1,413 @@ + + + + + diff --git a/pages/upload/camera_capture.vue b/pages/upload/camera_capture.vue deleted file mode 100644 index a1b03e0..0000000 --- a/pages/upload/camera_capture.vue +++ /dev/null @@ -1,263 +0,0 @@ - - - - - diff --git a/uni_modules/ima-camera-view/changelog.md b/uni_modules/ima-camera-view/changelog.md new file mode 100644 index 0000000..965db49 --- /dev/null +++ b/uni_modules/ima-camera-view/changelog.md @@ -0,0 +1,438 @@ +## 1.2.2(2026-06-11) +> 新增功能 + +- 1、**iOS 端补齐 `previewRotation` 支持**:`index.vue` 新增 `previewRotation` prop 与 `changePreviewRotation` 方法,`index.uts` 导出 `setPreviewRotation`,`ImaCameraManager.swift` 通过 `CGAffineTransform(rotationAngle:)` 实现预览层旋转(与 Android 行为对齐)。 + +> 问题修复 + +- 1、**修复首次进入时 `previewRotation` 初始值 90° 无效**:`initCameraView()` 现在始终使用 `TextureView` 预览模式(不再等 `previewRotationDegrees != 0f` 才切换),避免初始化时用 `SurfaceView`、后续 prop 到达时 `setPreview(TEXTURE)` 触发相机重启导致旋转丢失。 +- 2、**修复 `setPreviewRotation(0)` 不生效**:`applyPreviewRotation()` 移除 `previewRotationDegrees == 0f` 提前返回,0° 时显式重置 `cv.rotation = 0f` 及 `scaleX/Y = 1f`。 +- 3、**修复旋转切换按钮点击无效**:`NVLoad()` 中在 `initCameraView()` 之前调用 `setPreviewRotation(this.previewRotation)`,确保原生 CameraView 创建时已读取旋转角度;`NVLayouted()` 增加安全网再次应用旋转。 +- 4、**修复首次进入时 `onCameraOpened` 中 `$refs.cameraRef` 可能未就绪**:使用 `$nextTick` 延迟调用 `applyPreviewRotation()`;picture→video 模式切换延迟从 300ms 延长至 800ms,并在切换前同步调用一次旋转。 +## 1.2.1(2026-06-10) +> 新增功能 + +- 1、**外接摄像头预览旋转修正(Android)**:新增 `previewRotation` 属性及 `changePreviewRotation` 方法,用于修正无内置摄像头设备(如平板)外接 USB 摄像头时预览画面方向错误的问题;支持 `0` / `90` / `180` / `270`(或 `-90` 等等效角度)。 +- 2、设备旋转时自动保持预览修正方向不变(在 `onCameraOpened`、`onOrientationChanged` 时重新应用)。 + +> 问题修复 + +- 1、修复设置 `previewRotation` 后预览已正常、但**拍照输出图片方向仍不正确**的问题:拍照时会将 `previewRotation` 叠加到原生 `result.rotation` 后一并修正。 + +> 功能优化 + +- 1、启用 `previewRotation` 时自动切换为 `TextureView` 预览模式,并通过 `CameraView` 视图层旋转 + 缩放填充实现稳定预览(不依赖易被原生覆盖的 `TextureView.setTransform`)。 + +> 平台说明 + +- 本能力目前仅在 **`android`** 端实现;`ios` / `harmony` 暂未提供同等 API。 + +> 由于 **`harmony端`** 不支持兼容性组件,`harmony端`(指的是`harmony 5.0+`)不再本组件中更新,插件正在更新中 +## 1.2.0(2026-05-24) +> 新增功能 + +- 无 + +> 问题修复 + +- 无 + +> 功能优化 + +- 无 + +> 由于 **`harmony端`** 不支持兼容性组件,`harmony端`(指的是`harmony 5.0+`)不再本组件中更新,插件正在更新中 +## 1.1.16(2026-05-20) +> 新增功能 + +- 1、**预览圆角**:支持 `previewCornerRadius`、`previewCornerRadiusRate` 及 `changePreviewCorner`(圆形/多档圆角预览以原生实现为准)。 + +> 问题修复 + +- 1、修复「同页先预热 `video` 再轻触拍照」时,若在原生 `opened` 回调中无条件按 prop 再次 `changeMode`,会与原生「为拍照切换到 PICTURE 再在下一帧 `takePicture`」的逻辑冲突,导致预览反复关闭/打开、拍照异常的问题(已移除该盲目同步)。 +- 2、`nvue` / 部分运行时下 `$refs` 实例上 **`changeMode` 等方法不可用** 的问题:通过 **`mode` prop + `watch`** 同步原生模式,页面侧推荐使用 `:mode` 切换 `picture` / `video`。 + +> 功能优化 + +- 1、**`mode` prop** 增加监听:变更时调用原生 `setMode`,与 `changeMode` 行为对齐。 +- 2、录像相关:停止录像、开始时间戳等逻辑在主线程/时序上做了加固。 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) +## 1.1.15(2026-02-02) +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1、部分手机无法录像的问题或者录像中没有返回结果的问题(可能解决`{ "errorCode" => 5, "reason" => "录像失败", "message" => "java.lang.RuntimeException: start failed." }`的问题) + - 1.1、增加了待录像(切换 VIDEO 模式后延后执行) + - 1.2、待拍照(切换 PICTURE 模式后延后执行) + +> 功能优化 + +- 1、增加拍照、录像、结束录像时异常抛出 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.14(2026-01-30) +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1、部分手机无法录像的问题或者录像中没有返回结果的问题 +- 2、修改代码结构,准备改成兼容组件模式,为`Harmony Next`做准备 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) +## 1.1.13(2026-01-22) +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1、修复获取Activity实例、Application上下文上下文出现的问题! +- 2、修复相机按键、蓝牙自拍杆监听事件的问题 + +> 功能优化 + +- 1、相机震动做了兼容处理 +- 2、相机的权限申请做了兼容处理 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.12(2026-01-19) +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1、修复安卓8.1事打开相机报错:“相机初始失败或者当前设备不支持:创建失败:When targetSdkVersion >= 33 + should use amdroid.permission.xxx,...” + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) +## 1.1.11(2026-01-07) + +> 新增功能(临时更新) + +- 1、增加`take-error(相机拍摄监测)`、`orientation-change(相机角度转换)`、、`camera-change(相机设置监听)` + +> 问题修复 + +- 1、在`setSizeSelectors`方法增加错误回调,便于排查一些手机调取无反应的问题 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.10(2026-01-07) + +> 新增功能(临时更新) + +- 1、增加`take-error(相机拍摄监测)`、`orientation-change(相机角度转换)`、、`camera-change(相机设置监听)` + +> 问题修复 + +- 1、在`setSizeSelectors`方法增加错误回调,便于排查一些手机调取无反应的问题 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.9(2026-01-06) + +> 新增功能(临时更新) + +- 1、新增加载相机基础参数方法`loadCameraView` + +> 问题修复 + +- 1、修复在 `HBuilderX 4.76` 及以下版本打包(包括自定义基座)时,在kotlin文件中无法获取当前 + `UTSAndroid.getUniActivity()`、 `UTSAndroid.getAppContext()`的问题 +- 2、修复在 `HBuilderX 4.76` 及以下版本打包(包括自定义基座)时白屏后闪退的问题 +- 3、修复高版本`安卓15+`及以上获取的SdkVersion值与当前应用实际的SdkVersion值不一致导致相机获取权限崩溃后闪退的问题 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.8(2026-01-05) + +> 新增功能(临时更新) + +- 1、是否将拍摄文件保存到本地可见媒体(即相册)的方法`changeGallery` + +> 问题修复 + +- 1、相机权限的问题,如用户拒绝后可直接跳转到当前 App 的系统设置页 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.7(2026-01-04) + +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1.1.6 版本推包后上传不成功的问题(下载和导入还是1.1.5的代码) + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.6(2026-01-04) + +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 1、安卓高版本(安卓16)出现拍照的问题 +- 2、在一些其他终端设备(非手机)中出现相机预览画面与实际不符合的问题`【待复测】` +- 3、一些配置不生效的问题,如changeAspectRatio、changeOrientation(由于相机加载顺序问题导致的) +- 4、一些其他终端设备(非手机)进入卡顿或者黑屏几秒才显示相机预览页面`【待复测】` +- 5、一些手机设备由于权限问题导致第一次进入是黑屏或者后几次进入偶尔出现黑屏闪现的问题`【待复测】` + +> 功能优化 + +- 1、将之前的uts改成了kotlin的写法 +- 2、将组件是的抛出调整成`CameraManager.setCameraCallback`,方便后期增加参数输出、控制 +- 3、优化了相机加载的顺序问题、以及设置相机时的问题 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +## 1.1.5(2025-12-29) + +> 新增功能(临时更新) + +- 新增设置相机使用设备方向的方法`changeOrientation` +- 新增设置相机网格及颜色的方法`changeGrid` + +> 问题修复 + +- 无 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新(已完成开发,测试中) + +## 1.1.4(2025-12-28) + +> 新增功能(临时更新) + +- 新增设置曝光值的方法`changeExposure` + +> 问题修复 + +- 修复动态权限申请的问题(即Android 12 及以下、Android 13+) +- 修复 Android 16(即API级别为36)时摄像回调的问题 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新 + +## 1.1.3(2025-12-02) + +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- 打包报错问题修复,(4.85版本有问题,4.76以下的版本未复现) +- 报错内容: + `ima-camera-view/utssdk/app-android/src/index.kt:723:55 Argument type mismatch: actual type is 'Any', but 'Number' was expected` + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新 + +## 1.1.2(2025-11-06) + +> 新增功能(临时更新) + +- 无 + +> 问题修复 + +- `快捷键拍照(蓝牙自拍杆、手机音量键)`拍照时,返回后按钮无法操作的问题修复 +- 页面在没启用`shortcut(快捷键拍照)`时,也会进入快捷键的问题修复 +- 修复在低版本`HubuildX`时打包出现找不到类型的问题 + +> 功能优化 + +- 优化了相机资源在进入时卡顿的问题 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新 + +## 1.1.1(2025-11-03) + +> 新增功能(临时更新) + +- 新增设置照片输出格式的方法`changeSuffix` + +> 问题修复 + +- 修复照片格式无法设置的问题【原因是在uni给出的生命周期内,无法取到`props`的参数,只能在`watch`中处理】 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新 + +## 1.1.0(2025-10-31) + +> 新增功能 + +- 快捷键拍照: 如:按两下音量键拍照、按音量键拍照等等(可自定义) +- 蓝牙自拍杆: 提供可以连接蓝牙自拍杆拍照、对焦等(可自定义) +- 相机`是否开启蓝牙自拍杆、手机快捷键拍照`,可自定义快捷键,具体参考参数`shortcut` +- + +> 问题修复 + +- 无 + +> 功能优化 + +- 无 + +> 计划新增功能(大版本更新【即 `1.2.0` 开始】) + +- 完善鸿蒙`Harmony`版本的并进行更新 + +## 1.0.5(2025-10-30) + +> 新增功能(临时更新) + +- 相机`录像`方法增加设置`视频录制时长限制` +- 相机`录像`声音默认系统录像声音,也可自定义,具体参考参数`recorder`、`sound2` + +> 问题修复 + +- 无 + +> 功能优化 + +- 无 + +## 1.0.4(2025-10-18) + +> 新增功能(临时更新) + +- 增加设置相机`白平衡`方法:`changeWhiteBalance` +- 增加设置相机`HDR`方法:`changeHdr` +- 增加设置相机`特定比例`方法:`changeAspectRatio` +- 新增了`widthRatio`、`heightRatio`、`tolerance`、`whiteBalance`、`hdr`、`shutter`、`sound`、`vibrate`、 + `duration`等参数,具体参考API + +> 问题修复 + +- 无 + +> 功能优化 + +- 照片文件的尺寸和手机原相机的尺寸不对的问题,可以通过参数`duration`去控制,其中`全屏`、`1:1` + 基本是和原相机尺寸一致的(测试了大部分手机型号都OK,个别手机`3:4`、`4:3`、`9:16`时会有少许容差,可以通过参数 + `duration`去控制) + +## 1.0.3(2025-10-16) + +> 新增功能 + +- 增加拍照声音,可以自定义声音文件(默认手机原相机声音) +- 增加拍照震动,可以自定义震动时长(默认200毫秒) + +> 问题修复 +> 无 + +> 功能优化 + +- 照片文件的分辨率取手机原相机的,提高照片的清晰度 + +## 1.0.2(2025-09-09) + +> 新增功能 +> 无 + +> 问题修复 +> 无 + +> 功能优化 + +- 支持拍照预览或从相册选择后,返回当前相机页面时,如果出现黑屏状态,可以重新自己手动拉起相机 + +## 1.0.1(2025-09-05) + +> 新增功能 +> 无 + +> 问题修复 + +- 修复高版本(`4.66`时)打包报错:`*(项目路径)*//index.kt:44:12 Unresolved reference: _uA`、 + `*(项目路径)*/index.kt:118:48 Unresolved reference: _uO`的问题 +- 修复前置拍出来的图片是镜像的问题 +- 修复照片拍出来尺寸不对、照片过小的问题 + +> 功能优化 +> 无 + +## 1.0.0(2025-05-27) + +> 新增功能 + +- 新增方法:`close`、 `open`、 `takePhoto`、 `takePhotoSnapshot`、 `takeVideo`、`takeVideoSnapshot`、 + `stopVideo`、 `changeZoom`、 `changeFacing`、`changeFlash`、`changeAudio` +- 新增事件:`onPictureTaken`、 `onVideoTakenStart`、 `onVideoTakenEnd`、 `onFocusStart`、 `onFocusEnd` +- `android端`的所有功能已完成开发、测试 +- `harmony端`计划开发中 +- 初始版 + +> 问题修复 +> 无 + +> 功能优化 +> 无 diff --git a/uni_modules/ima-camera-view/encrypt b/uni_modules/ima-camera-view/encrypt new file mode 100644 index 0000000..ddb19ca Binary files /dev/null and b/uni_modules/ima-camera-view/encrypt differ diff --git a/uni_modules/ima-camera-view/package.json b/uni_modules/ima-camera-view/package.json new file mode 100644 index 0000000..4686ee0 --- /dev/null +++ b/uni_modules/ima-camera-view/package.json @@ -0,0 +1,126 @@ +{ + "id": "ima-camera-view", + "displayName": "原生Camera自定义相机拍照、视频录制", + "version": "1.2.2", + "description": "原生Camera相机开发的UTS插件,支持相机拍照、视频录制、可实现点击聚焦、手势缩放、自定义布局、自定义蒙版(用于人脸拍照,身份证拍照等),同时支持蓝牙自拍杆(可自定义)、手机快捷键(可自定义)", + "keywords": [ + "原生Camera", + "相机拍照", + "视频录制", + "自定义布局相机", + "自定义蒙版相机" +], + "repository": "", + "engines": { + "HBuilderX": "^4.8.1", + "uni-app": "^4.81", + "uni-app-x": "^4.81" + }, + "dcloudext": { + "type": "component-uts", + "sale": { + "regular": { + "price": "19.99" + }, + "sourcecode": { + "price": "299.00" + } + }, + "contact": { + "qq": "488266488" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "摄像头、音频、文件读取、文件写入\n \n \n \n \n " + }, + "npmurl": "", + "darkmode": "x", + "i18n": "x", + "widescreen": "√" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": { + "extVersion": "1.1.13", + "minVersion": "" + }, + "vue3": { + "extVersion": "1.1.13", + "minVersion": "" + } + }, + "web": { + "safari": "x", + "chrome": "x" + }, + "app": { + "vue": { + "extVersion": "1.1.13", + "minVersion": "" + }, + "nvue": { + "extVersion": "1.1.13", + "minVersion": "" + }, + "android": { + "extVersion": "1.1.13", + "minVersion": "21" + }, + "ios": "x", + "harmony": { + "extVersion": "1.1.13", + "minVersion": "5.0以下(不包括5.0)" + } + }, + "mp": { + "weixin": "x", + "alipay": "x", + "toutiao": "x", + "baidu": "x", + "kuaishou": "x", + "jd": "x", + "harmony": "x", + "qq": "x", + "lark": "x", + "xhs": "-" + }, + "quickapp": { + "huawei": "x", + "union": "x" + } + }, + "uni-app-x": { + "web": { + "safari": "x", + "chrome": "x" + }, + "app": { + "android": { + "extVersion": "1.1.13", + "minVersion": "21" + }, + "ios": "x", + "harmony": { + "extVersion": "1.1.13", + "minVersion": "5.0以下(不包括5.0)" + } + }, + "mp": { + "weixin": "x" + } + } + } + } + } +} diff --git a/uni_modules/ima-camera-view/readme.md b/uni_modules/ima-camera-view/readme.md new file mode 100644 index 0000000..c95c19d --- /dev/null +++ b/uni_modules/ima-camera-view/readme.md @@ -0,0 +1,373 @@ +# 原生自定义相机拍照、视频录制 (ima-camera-view) + +`原生自定义相机拍照、视频录制 (ima-camera-view)`是基于原生相机开发的UTS插件,支持`相机拍照`、`视频录制` +、可实现`点击聚焦`、`手势缩放`、 +`自定义布局`、`自定义蒙版`(用于人脸拍照,身份证拍照等)。 + +## ⚠️注意️ +由于之前技术选型不支持继续扩展相机的新特性,`本插件(ima-camera-view)继续维护,只修复现存的一些bug,不再新增新功能`, +建议使用ima-camerax-view这个相机组件插件,[ima-camerax-view 地址](https://ext.dcloud.net.cn/plugin?name=ima-camerax-view), +如果不追求如:**超广角镜头切换(0.5x,`changeWideAngle`)**、**按倍率缩放(`setCameraZoom`,如 0.5 / 1.0 / 2.0)**、**多摄逻辑镜头切换**、 +**Camera2 白平衡 / HDR / 曝光补偿**、**录像进度(`onVideoTakenProgress`)与设备方向变化(`onOrientationChanged`)回调**等新特性的话,扔建议继续使用本插件。 + +- `ima-camerax-view【新插件】`:[插件地址](https://ext.dcloud.net.cn/plugin?name=ima-camerax-view) +- `ima-camera-view【本插件】`:[插件地址](https://ext.dcloud.net.cn/plugin?name=ima-camera-view) +- `ima-camerax-view【新插件】`与 `ima-camera-view【本插件】`组件 API 保持基本一致,便于从 CameraView 版平滑迁移 + +## 支持功能 + +- 打开、关闭摄像头预览 +- 拍照、快照拍照 +- 录制视频、快照录制视频 +- 设置摄像头缩放级别 +- 设置相机白平衡 +- 设置相机HDR +- 设置相机曝光 +- 设置摄像头方向 +- 设置闪光灯模式 +- 设置相机使用设备方向 +- 设置相机网格及颜色 +- 设置音频(录制视频时) +- 设置圆角、圆预览(可自定义) +- 外接摄像头预览方向修正(`previewRotation`,Android) +- 设置拍照、录制视频的声音(可自定义) +- 蓝牙自拍杆(可自定义) +- 手机快捷键(可自定义) + +## 自定义调整 + +- 自定义调整页面地址:`uni_modules/ima-camera-view/utssdk/app-android/index.vue` +- 蓝牙自拍杆、手机快捷键的自定义,可以参考文件中的`shortcutListener`方法 +- 设置拍照、录制视频的声音,可以参考文件中的`photoSound`、`videoSound`方法 + +## 需要权限 + +- 摄像头、音频、文件读取、文件写入、震动 + +```text +"android.permission.CAMERA", +"android.permission.RECORD_AUDIO", +"android.permission.VIBRATE" +"android.permission.READ_EXTERNAL_STORAGE" +"android.permission.WRITE_EXTERNAL_STORAGE" +``` + +- 即:在`manifest.json`中的`distribute.android.permissions`加入 + +```text +// 拍摄照片和视频时需要 + +// 拍摄视频时需要Audio.ON(默认) + +// 读取拍照、录像文件文件时需要 + +// 报错拍照、录像文件文件时需要(默认保存到沙盒缓存) + +// 震动权限 + +``` + +## 快门声音素材 + +- 将需要的快门声音放在`uni_modules/ima-camera-view/utssdk/app-android/assets`下即可 +- [熊猫办公](https://www.tukuppt.com/yinxiaomuban/kuaimenshengyin.html) +- [站长素材](https://sc.chinaz.com/tag_yinxiao/kuaimen.html) + +## 使用示例【此示例的代码只实现了`相机拍照`的逻辑,更多示例请导入项目】 + +- 新建一个`camera.nvue`的文件 +- ⚠️注意️:只能在`.nvue`、`.uvue`的文件后缀下才生效,不支持`.vue` + +```nvue + + + + + +``` + +## 外接摄像头方向修正(Android) + +适用于**无内置摄像头**或外接 USB 摄像头的设备(如横屏平板、工控一体机)。当物理安装的摄像头与屏幕方向不一致,导致预览画面旋转 90° 等情况时,可通过 `previewRotation` 固定修正预览与拍照方向。 + +### 使用方式 + +**方式一:属性(推荐)** + +```nvue + +``` + +**方式二:方法动态调整** + +```javascript +this.$refs.cameraRef.changePreviewRotation(90) // 顺时针 90° +this.$refs.cameraRef.changePreviewRotation(-90) // 逆时针 90°(等价 270°) +``` + +### 参数说明 + +| 取值 | 说明 | +|------|------| +| `0` | 不修正(默认) | +| `90` / `-270` | 顺时针旋转 90° | +| `180` / `-180` | 旋转 180° | +| `270` / `-90` | 顺时针旋转 270°(逆时针 90°) | + +### 注意事项 + +- 仅 **`android`** 端生效;与 `orientation`(设备方向跟随)不同,`previewRotation` 用于**固定补偿外接摄像头安装角度**,不随手机旋转而改变。 +- 启用非 `0` 的 `previewRotation` 后,组件会自动使用 `TextureView` 预览;拍照结果会同步叠加该角度修正。 +- 若预览方向仍不对,请依次尝试 `90`、`-90`、`180`,以实际安装方向为准。 +- 录像方向暂未做同等叠加修正;若录像也有方向问题,可在业务层二次处理或反馈 issue。 + +## 常见的比例的定义(widthRatio,heightRatio) + +```typescript +// 正方形 +AspectRatio.of(1, 1) // 1:1 + +// 竖屏比例 +AspectRatio.of(9, 16) // 9:16 (手机竖屏) +AspectRatio.of(3, 4) // 3:4 +AspectRatio.of(2, 3) // 2:3 +AspectRatio.of(10, 16) // 10:16 (5:8) + +// 横屏比例 +AspectRatio.of(16, 9) // 16:9 (宽屏) +AspectRatio.of(4, 3) // 4:3 (传统) +AspectRatio.of(3, 2) // 3:2 (照片) +AspectRatio.of(16, 10) // 16:10 (8:5) +AspectRatio.of(21, 9) // 21:9 (超宽屏) + +// 建议比例 +const AspectRatios = { + // 1:1 正方形 + SQUARE: AspectRatio.of(1, 1), + // 9:16 竖屏(手机默认) + PORTRAIT: AspectRatio.of(9, 16), + // 16:9 横屏 + LANDSCAPE: AspectRatio.of(16, 9), + // 3:4 传统照片比例 + THREE_FOUR: AspectRatio.of(3, 4), + // 4:3 传统相机比例 + FOUR_THREE: AspectRatio.of(4, 3) +} +``` + +## 不同场景的推荐值(tolerance) + +```typescript +const TOLERANCE = { + STRICT: 0.01.toFloat(), // 非常严格,几乎精确匹配 + STANDARD: 0.05.toFloat(), // 标准,推荐使用 + FLEXIBLE: 0.1.toFloat(), // 灵活,兼容更多设备 + LOOSE: 0.2.toFloat() // 宽松,可能匹配到意外比例 +} +``` + +## Api + +| 属性 | 类型 | 默认值 | 说明 | 平台 | +|---------------|-----------------|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| widthRatio | Number | 0 | 照片尺寸比率(宽度): 默认全屏(若widthRatio为9,heightRatio为16,则为9:16、widthRatio为3,heightRatio为4,则为3:4...)不建议值过大,常用的比例有1:1、3:4、4:3、9:16... | `android` | +| heightRatio | Number | 0 | 照片尺寸比率(高度): 默认全屏(若widthRatio为9,heightRatio为16,则为9:16、widthRatio为3,heightRatio为4,则为3:4...)不建议值过大,常用的比例有1:1、3:4、4:3、9:16... | `android` | +| tolerance | Number | 0.1 | 照片尺寸容差值: 建议设为 0.05~0.15,以便稍微兼容不同设备相机实际比例差异 ,值为:0~1 | `android` | +| whiteBalance | iWhiteBalance | "auto" | 白平衡模式: auto(自动)、incandescent(白炽)、fluorescent(荧光)、daylight(日光)、cloudy(多云) 、loudy(多云【慎用:`兼容1.1.3版本前单词拼错的问题,将在1.2.0大版本更新后删除,建议1.1.3后的版本使用cloudy`】) | `android` | +| hdr | iHdr | "off" | HDR模式: off(关闭)、on(开启) | `android` | +| facing | iFacing | "back" | 后置、前置摄像头: back(后置摄像头)、front(前置摄像头) | `android` | +| flash | iFlash | "off" | 闪光灯: off(关闭)、on(开启)、auto(自动)、torch(常开) | `android` | +| audio | iAudio | "on" | 音频: on(开启)、off(关闭)、mono(单声道)、stereo(立体声) | `android` | +| orientation | iOrientation | "auto" | 方向: auto(自动)、portrait(竖屏)、landscape(横屏) 【注意:`目前竖屏、横屏拍出来都为竖屏方式,这两个参数的使用效果一致`,为预留参数,为后期做准备】 | `android` | +| grid | iGrid | "off" | 网格: off(关闭)、draw_3X3(3x3)、draw_4x4(4x4)、draw_phi(phi) | `android` | +| gridColor | String | "#808080" | 颜色值: 只支持如:#fff、#ffffff、#......等类型的颜色值 | `android` | +| photoSuffix | iPhotoSuffix | "jpeg" | 照片格式: jpeg、jpg | `android` | +| mode | String | 'picture' | 相机模式: picture(拍照)、video(录视频) | `android` | +| previewCornerRadius | Number | 0 | 预览圆角半径(px);与 `previewCornerRadiusRate` 二选一或组合使用 | `android` | +| previewCornerRadiusRate | Number | 0 | 预览圆角比例(相对短边);`0.5` 且预览区域为正方形时为圆形预览 | `android` | +| previewRotation | Number | 0 | 外接摄像头预览/拍照方向修正角度:`0`、`90`、`180`、`270`(支持负值如 `-90`);详见上文「外接摄像头方向修正」 | `android` | +| gallery | Boolean | false | 是否将拍照、录像文件保存到系统相册(可见媒体库) | `android` | +| shutter | Boolean | true | 是否打开拍照声音: true(开启,此时配置`sound`才起作用)、false(关闭) | `android` | +| sound | String | '' | 相机拍照声音文件: 将mp3音频文件放在`uni_modules/ima-camera-view/utssdk/app-android/assets`下即可,为音频文件的名称,如`xxx.mp3`,默认手机原声 | `android` | +| recorder | Boolean | true | 是否打开录像声音: true(开启,此时配置`sound2`才起作用)、false(关闭) | `android` | +| sound2 | String | '' | 相机录像声音文件: 将mp3音频文件放在`uni_modules/ima-camera-view/utssdk/app-android/assets`下即可,为音频文件的名称,如`xxx.mp3`,默认手机原声 | `android` | +| vibrate | Boolean | false | 是否打开拍照震动: true(开启,此时配置`duration`才起作用)、false(关闭) | `android` | +| duration | Number | 300 | 是否打开拍照震动时长,单位:毫秒(ms) | `android` | +| shortcut | Boolean | false | 是否开启蓝牙自拍杆、手机快捷键拍照: false(关闭)、true(开启) | `android` | + +## 方法 + +### 共同 方法/* */ + +| 方法名称 | 说明 | 方法参数 | 平台 | +|-------------------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------|-------------| +| open | 打开摄像头预览 | 无 | `android` | +| close | 关闭摄像头预览 | 无 | `android` | +| takePhoto | 拍照(标准拍照流程) | 无 | `android` | +| takeVideo(duration) | 开始录制视频 | duration:拍摄时长,单位:毫秒(ms)【0 表示不限制】 | `android` | +| stopVideo | 停止视频录制 | 无 | `android` | +| changeZoom(zoom) | 设置摄像头缩放级别 | zoom:缩放倍数(浮点数) | `android` | +| changeExposure(exposure) | 设置曝光值 | exposure:曝光值(浮点数)【值为:-2~2,默认为0】 | `android` | +| changeWhiteBalance(whiteBalance) | 设置相机白平衡 | whiteBalance:参考`api`中的`whiteBalance`参数 | `android` | +| changeHdr(hdr) | 设置相机HDR | hdr:参考`api`中的`hdr`参数 | `android` | +| changeFacing((facing)) | 设置摄像头方向 | facing:参考`api`中的`facing`参数 | `android` | +| changeFlash(flash) | 设置闪光灯模式 | flash:参考`api`中的`flash`s参数 | `android` | +| changeOrientation(orientation) | 设置相机使用设备方向 | orientation:参考`api`中的`orientation`s参数 | `android` | +| changeGrid(grid,color) | 设置相机网格及颜色 | grid:参考`api`中的`grid`参数, color: 参考`api`中的`gridColor`参数 | `android` | +| changeAudio(audio) | 设置音频 | audio:参考`api`中的`audio`参数 | `android` | +| changeSuffix(suffix) | 设置照片输出格式 | suffix:参考`api`中的`photoSuffix`参数 | `android` | +| changeSizeSelectors(width,height,tolerance) | 设置相机特定比例/分辨率 | width、height、tolerance 参考 `api` 中同名属性;`0` 表示使用屏幕宽高 | `android` | +| changePreviewCorner(radius,radiusRate) | 设置预览圆角 | radius: 圆角 px;radiusRate: 圆角比例(正方形下 `0.5` 为圆形) | `android` | +| changePreviewRotation(degrees) | 设置外接摄像头预览/拍照方向修正 | degrees: `0` / `90` / `180` / `270`(支持负值);仅 Android | `android` | +| changeGallery(gallery) | 是否保存到系统相册 | gallery: `true` / `false` | `android` | +| changeMode(mode) | 设置相机模式 | mode: `picture` / `video`;也可直接使用 `:mode` prop | `android` | +| takePhotoSnapshot | 快照拍照(适用于快速拍照场景) | 无 | `android` | +| takeVideoSnapshot(duration) | 快照方式录制视频 | duration:拍摄时长,单位:毫秒(ms)【0 表示不限制】 | `android` | + +## 事件 + +| 事件名称 | 说明 | 回调参数 | 平台 | +|---------------------|---------------|-----------------------------------|-------------| +| onPictureTaken | 拍照返回数据 | ({path,width,height}: any) => {} | `android` | +| onVideoTakenStart | 录制视频开始事件 | () => {} | `android` | +| onVideoTakenEnd | 录制视频结束事件 | ({path,size}: any) => {} | `android` | +| onFocusStart | 自动对焦开始 | ({x,y}: any) => {} | `android` | +| onFocusEnd | 自动对焦结束 | ({x,y,focus}: any) => {} | `android` | +| onOrientationChange | 设备方向变化 | ({angle,orientation,isPortrait,isLandscape}: any) => {} | `android` | +| onCameraOpened | 相机已打开 | (data: any) => {} | `android` | +| onCameraClosed | 相机已关闭 | (data: any) => {} | `android` | +| onCameraError | 相机错误 | ({errorCode,reason,message}: any) => {} | `android` | + diff --git a/uni_modules/ima-camera-view/utssdk/app-android/AndroidManifest.xml b/uni_modules/ima-camera-view/utssdk/app-android/AndroidManifest.xml new file mode 100644 index 0000000..152ab10 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-android/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uni_modules/ima-camera-view/utssdk/app-android/ImaCamera.kt b/uni_modules/ima-camera-view/utssdk/app-android/ImaCamera.kt new file mode 100644 index 0000000..d83840e Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/ImaCamera.kt differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraListener.kt b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraListener.kt new file mode 100644 index 0000000..e9a4eb9 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraListener.kt differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraPermission.kt b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraPermission.kt new file mode 100644 index 0000000..f1e3b3e Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraPermission.kt differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraUtils.kt b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraUtils.kt new file mode 100644 index 0000000..3f43360 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/ImaCameraUtils.kt differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter1.mp3 b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter1.mp3 new file mode 100644 index 0000000..f09bfc8 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter1.mp3 differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter2.mp3 b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter2.mp3 new file mode 100644 index 0000000..63d408b Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter2.mp3 differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter3.mp3 b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter3.mp3 new file mode 100644 index 0000000..1fc85a6 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/assets/shutter3.mp3 differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/config.json b/uni_modules/ima-camera-view/utssdk/app-android/config.json new file mode 100644 index 0000000..8e23c10 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-android/config.json @@ -0,0 +1,9 @@ +{ + "minSdkVersion": 21, + "dependencies": [ + { + "id": "com.otaliastudios:cameraview", + "source": "implementation('com.otaliastudios:cameraview:2.7.2') { exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'; exclude group: 'androidx.core', module: 'core' }" + } + ] +} \ No newline at end of file diff --git a/uni_modules/ima-camera-view/utssdk/app-android/index.uts b/uni_modules/ima-camera-view/utssdk/app-android/index.uts new file mode 100644 index 0000000..7f759f1 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-android/index.uts differ diff --git a/uni_modules/ima-camera-view/utssdk/app-android/index.vue b/uni_modules/ima-camera-view/utssdk/app-android/index.vue new file mode 100644 index 0000000..ea3e210 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-android/index.vue @@ -0,0 +1,651 @@ + + + diff --git a/uni_modules/ima-camera-view/utssdk/app-ios/ImaCameraManager.swift b/uni_modules/ima-camera-view/utssdk/app-ios/ImaCameraManager.swift new file mode 100644 index 0000000..c7f16e1 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-ios/ImaCameraManager.swift differ diff --git a/uni_modules/ima-camera-view/utssdk/app-ios/Info.plist b/uni_modules/ima-camera-view/utssdk/app-ios/Info.plist new file mode 100644 index 0000000..bf6c988 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-ios/Info.plist @@ -0,0 +1,14 @@ + + + + + NSCameraUsageDescription + 需要您的同意才能使用摄像头进行拍照和录像 + NSMicrophoneUsageDescription + 需要您的同意才能录制视频中的声音 + NSPhotoLibraryUsageDescription + 需要您的同意才能将拍摄的照片和视频保存到相册 + NSPhotoLibraryAddUsageDescription + 需要您的同意才能将拍摄的照片和视频保存到相册 + + diff --git a/uni_modules/ima-camera-view/utssdk/app-ios/config.json b/uni_modules/ima-camera-view/utssdk/app-ios/config.json new file mode 100644 index 0000000..e895ab1 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-ios/config.json @@ -0,0 +1,10 @@ +{ + "deploymentTarget": "12.0", + "frameworks": [ + "AVFoundation", + "Photos", + "UIKit", + "Foundation", + "AudioToolbox" + ] +} diff --git a/uni_modules/ima-camera-view/utssdk/app-ios/index.uts b/uni_modules/ima-camera-view/utssdk/app-ios/index.uts new file mode 100644 index 0000000..2951349 Binary files /dev/null and b/uni_modules/ima-camera-view/utssdk/app-ios/index.uts differ diff --git a/uni_modules/ima-camera-view/utssdk/app-ios/index.vue b/uni_modules/ima-camera-view/utssdk/app-ios/index.vue new file mode 100644 index 0000000..2b01ee3 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/app-ios/index.vue @@ -0,0 +1,634 @@ + + + diff --git a/uni_modules/ima-camera-view/utssdk/interface.uts b/uni_modules/ima-camera-view/utssdk/interface.uts new file mode 100644 index 0000000..a47f9e2 --- /dev/null +++ b/uni_modules/ima-camera-view/utssdk/interface.uts @@ -0,0 +1,15 @@ +export type iWhiteBalance = 'auto' | 'incandescent' | 'fluorescent' | 'daylight' | 'cloudy' | 'loudy' + +export type iHdr = 'on' | 'off' + +export type iFacing = 'front' | 'back' + +export type iOrientation = 'auto' | 'portrait' | 'landscape' + +export type iGrid = 'off' | 'draw_3x3' | 'draw_4x4' | 'draw_phi' + +export type iFlash = 'on' | 'auto' | 'torch' | 'off' + +export type iAudio = 'on' | 'off' | 'mono' | 'stereo' + +export type iPhotoSuffix = 'jpeg' | 'jpg' \ No newline at end of file diff --git a/uni_modules/lime-camera/changelog.md b/uni_modules/lime-camera/changelog.md new file mode 100644 index 0000000..8f00993 --- /dev/null +++ b/uni_modules/lime-camera/changelog.md @@ -0,0 +1,20 @@ +## 0.1.0(2025-09-11) +- fix: 修复uniappx nvue无法创建context的问题 +## 0.0.9(2025-09-11) +- feat: uniapp nvue +## 0.0.8(2025-05-25) +- fix: 修复uniapp 安卓转js问题 +## 0.0.7(2025-01-11) +- feat: 优化报错 +## 0.0.6(2024-12-05) +- fix: 修复变量重复 +## 0.0.5(2024-12-04) +- fix: UniPointerEvent改为UTSJSONObejct +## 0.0.4(2024-11-27) +- fix: 修复录像BUG +## 0.0.3(2024-04-21) +- feat: 增加点击对焦 +## 0.0.2(2024-03-29) +- fix: 修复默认值是前置的情况无效 +## 0.0.1(2024-03-17) +- init diff --git a/uni_modules/lime-camera/components/lime-camera/lime-camera.uvue b/uni_modules/lime-camera/components/lime-camera/lime-camera.uvue new file mode 100644 index 0000000..f9d34a5 --- /dev/null +++ b/uni_modules/lime-camera/components/lime-camera/lime-camera.uvue @@ -0,0 +1,101 @@ + + + diff --git a/uni_modules/lime-camera/components/lime-camera/lime-camera.vue b/uni_modules/lime-camera/components/lime-camera/lime-camera.vue new file mode 100644 index 0000000..11d5d7c --- /dev/null +++ b/uni_modules/lime-camera/components/lime-camera/lime-camera.vue @@ -0,0 +1,114 @@ + + + \ No newline at end of file diff --git a/uni_modules/lime-camera/encrypt b/uni_modules/lime-camera/encrypt new file mode 100644 index 0000000..13a6188 --- /dev/null +++ b/uni_modules/lime-camera/encrypt @@ -0,0 +1,2 @@ +SrFN>S(Z```rc.yWr)SS?ӎEzv/s|z۪ +P.,L9=rF:#ht~~ܤ;?mLN+0avљO \ No newline at end of file diff --git a/uni_modules/lime-camera/package.json b/uni_modules/lime-camera/package.json new file mode 100644 index 0000000..e0c3087 --- /dev/null +++ b/uni_modules/lime-camera/package.json @@ -0,0 +1,104 @@ +{ + "id": "lime-camera", + "displayName": "lime-camera 相机", + "version": "0.1.0", + "description": "lime-camera是参照小程序的camera组件和createCameraContext API实现的uts相机插件,目前只支持安卓", + "keywords": [ + "lime-camera", + "createCameraContext", + "camera", + "相机", + "uts" +], + "repository": "", + "engines": { + "HBuilderX": "^4.04", + "uni-app": "^4.73", + "uni-app-x": "^4.74" + }, + "dcloudext": { + "type": "component-uts", + "sale": { + "regular": { + "price": "68.00" + }, + "sourcecode": { + "price": "168.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "\n\t\n\t\n\t" + }, + "npmurl": "", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "√", + "aliyun": "√", + "alipay": "√" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "-", + "vue3": "-" + }, + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "vue": "-", + "nvue": "√", + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-", + "alipay": "-", + "toutiao": "-", + "baidu": "-", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "-", + "lark": "-" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": { + "extVersion": "", + "minVersion": "21" + }, + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/lime-camera/readme.md b/uni_modules/lime-camera/readme.md new file mode 100644 index 0000000..6432944 --- /dev/null +++ b/uni_modules/lime-camera/readme.md @@ -0,0 +1,114 @@ +# lime-camera 相机 +- 参照小程序的`camera`组件和`createCameraContext`API实现。 + +## 安装 +导入插件后,自定义基座再使用,请先试用后谨慎购买,一但购买没有退货。 + +### 基础使用 + +```html + + + + + + + + + + +``` + +```js +import { + createCameraContext, + TakePhotoOption, + TakePhotoSuccessCallbackResult, + CameraContextSetZoomOption, + SetZoomSuccessCallbackResult, + CameraContextStartRecordOption, + GeneralCallbackResult, + CameraContextStopRecordOption, + StopRecordSuccessCallbackResult + } from '@/uni_modules/lime-camera' +const context = createCameraContext() + +const flash = ref('off') +const device = ref('back') +const imagePath = ref('') +const onError = (err:any) => { + console.log('err', err) +} + +const toggleFlash = ()=>{ + flash.value = flash.value == 'on' ? 'off' : 'on' +} +const toggledevice = ()=>{ + device.value = device.value == 'back' ? 'front' : 'back' +} +const takePhoto = ()=>{ + let time = Date.now() + context.takePhoto({ + success: (res:TakePhotoSuccessCallbackResult)=> { + console.log('takePhoto time', Date.now() - time) + imagePath.value = res.tempImagePath + console.log('takePhoto', res.tempImagePath) + } + } as TakePhotoOption) +} +const setZoom = ()=>{ + context.setZoom({ + zoom: Math.random() * 10, + success: (res:SetZoomSuccessCallbackResult)=> { + console.log('setZoom', res.errMsg, res.zoom) + } + } as CameraContextSetZoomOption) +} + +const startRecord = ()=>{ + context.startRecord({ + success(res: GeneralCallbackResult){ + console.log('startRecord') + } + } as CameraContextStartRecordOption) +} +const stopRecord = ()=>{ + context.stopRecord({ + success(result: StopRecordSuccessCallbackResult){ + console.log('stopRecord', result.tempThumbPath) + } + } as CameraContextStopRecordOption) +} +let listener = context.onCameraFrame() +const startFrame = ()=>{ + listener.start() +} +const stopFrame = ()=>{ + listener.stop() +} +``` + +## Props +因为直接参照小程序`camera`组件,所以可以直接按[camera](https://uniapp.dcloud.net.cn/component/camera.html)文档来。但不支持扫码。扫码可以使用[lime-scan](https://ext.dcloud.net.cn/plugin?id=16452) + + +| 参数 | 说明 | 类型 | 默认值 | +| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ | +| focus | 是否开启点击对焦 | boolean | `false` | + +## 事件 + +| 参数 | 说明 | 类型 | 默认值 | +| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ | +| @click | (event:UniEvent) => {} | UniEvent | | + + +## API +因为直接参照小程序`createcameracontext`API,所以可以直接按[createcameracontext](https://uniapp.dcloud.net.cn/api/media/camera-context.html#createcameracontext)文档来。
+但`onCameraFrame`里的回调中的data为`ImageProxy` +```ts +context.onCameraFrame((frame)=>{ + // 这里是 ImageProxy + frame.data +}) +``` diff --git a/uni_modules/lime-camera/utssdk/app-android/AndroidManifest.xml b/uni_modules/lime-camera/utssdk/app-android/AndroidManifest.xml new file mode 100644 index 0000000..3b13ea1 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-android/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-android/camera.uts b/uni_modules/lime-camera/utssdk/app-android/camera.uts new file mode 100644 index 0000000..ee4d054 Binary files /dev/null and b/uni_modules/lime-camera/utssdk/app-android/camera.uts differ diff --git a/uni_modules/lime-camera/utssdk/app-android/config.json b/uni_modules/lime-camera/utssdk/app-android/config.json new file mode 100644 index 0000000..3a1b2a2 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-android/config.json @@ -0,0 +1,20 @@ +{ + "minSdkVersion": "21", + "dependencies": [ + // 使用camera2实现的CameraX核心库 + // 定义camerax_version为"1.4.0-alpha04" + // 下面的行是可选的,因为core库通过camera-camera2间接包含 + "androidx.camera:camera-core:1.4.0-alpha04" + "androidx.camera:camera-camera2:1.4.0-alpha04" + // 如果你想要额外使用CameraX生命周期库 + "androidx.camera:camera-lifecycle:1.4.0-alpha04" + // 如果你想要额外使用CameraX视频捕获库 + "androidx.camera:camera-video:1.4.0-alpha04" + // 如果你想要额外使用CameraX视图类 + "androidx.camera:camera-view:1.4.0-alpha04" + // 如果你想要额外添加CameraX ML Kit Vision集成 + // "androidx.camera:camera-mlkit-vision:1.4.0-alpha04" + // 如果你想要额外使用CameraX扩展库 + // "androidx.camera:camera-extensions:1.4.0-alpha04" + ] +} \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-android/index.uts b/uni_modules/lime-camera/utssdk/app-android/index.uts new file mode 100644 index 0000000..40f8f40 Binary files /dev/null and b/uni_modules/lime-camera/utssdk/app-android/index.uts differ diff --git a/uni_modules/lime-camera/utssdk/app-android/index.vue b/uni_modules/lime-camera/utssdk/app-android/index.vue new file mode 100644 index 0000000..6945aef --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-android/index.vue @@ -0,0 +1,274 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-harmony/builder.ets b/uni_modules/lime-camera/utssdk/app-harmony/builder.ets new file mode 100644 index 0000000..2abb9bd --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-harmony/builder.ets @@ -0,0 +1,372 @@ +import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'; +import { camera } from '@kit.CameraKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { image } from '@kit.ImageKit'; +import fs from '@ohos.file.fs'; + +@Component +struct CameraViewComponent { + @Prop mode: string = 'photo' + @Prop isFront: boolean = false + @Prop isFlash: boolean = false + @Prop isTorch: boolean = false + @Prop correctOrientation: boolean = false + @Prop @Watch('onCommandChange') command: string = '' // 指令 + + onTake?: (path: string) => void + + private xComponentCtl: XComponentController = new XComponentController(); + private xComponentSurfaceId: string = ''; + @State imageWidth: number = 1920; + @State imageHeight: number = 1080; + private cameraManager: camera.CameraManager | undefined = undefined; + private cameras: Array | Array = []; + private cameraPosition: number = 0 + private isFrontCamera = false + private cameraInput: camera.CameraInput | undefined = undefined; + private previewOutput: camera.PreviewOutput | undefined = undefined; + private photoOutput: camera.PhotoOutput | undefined = undefined; + private videoSession: camera.VideoSession | undefined = undefined; + private photoSession: camera.PhotoSession | undefined = undefined; + private uiContext: UIContext = this.getUIContext(); + private context: Context | undefined = this.uiContext.getHostContext(); + private cameraPermission: Permissions = 'ohos.permission.CAMERA'; + private isTorchOn: boolean = false + private isFlashOn: boolean = false + @State isShow: boolean = false; + + onCommandChange() { + let command = this.command.split('-')[0] + if (command == 'open') { + this.initCamera() + } else if (command == 'close') { + this.releaseCamera(); + } else if (command == 'take') { + this.takePhoto() + } else if (command == 'switch') { + this.isFrontCamera = this.isFront + this.switchCamera() + } else if (command == 'flash') { + this.isFlashOn = this.isFlash + this.onFlash() + } else if (command == 'torch') { + this.isTorchOn = this.isTorch + this.onTorch() + } + } + + async requestPermissionsFn(): Promise { + let atManager = abilityAccessCtrl.createAtManager(); + if (this.context) { + let res = await atManager.requestPermissionsFromUser(this.context, [this.cameraPermission]); + for (let i = 0; i < res.permissions.length; i++) { + if (this.cameraPermission.toString() === res.permissions[i] && res.authResults[i] === 0) { + this.isShow = true; + } + } + } + } + + async aboutToAppear() { + await this.requestPermissionsFn(); + } + + aboutToDisappear(): void { + this.releaseCamera(); + } + + // 初始化相机。 + async initCamera(): Promise { + // console.info(`initCamera previewOutput xComponentSurfaceId:${this.xComponentSurfaceId}`); + try { + // 获取相机管理器实例。 + this.cameraManager = camera.getCameraManager(this.context); + if (!this.cameraManager) { + console.error('initCamera getCameraManager'); + } + // 获取当前设备支持的相机device列表。 + this.cameras = this.cameraManager.getSupportedCameras(); + if (!this.cameras) { + console.error('initCamera getSupportedCameras'); + } + // 选择一个相机device,创建cameraInput输出对象。 + this.cameraInput = this.cameraManager.createCameraInput(this.cameras[this.cameraPosition]); + if (!this.cameraInput) { + console.error('initCamera createCameraInput'); + } + // 打开相机。 + await this.cameraInput.open().catch((err: BusinessError) => { + console.error(`initCamera open fail: ${err}`); + }) + // 获取相机device支持的profile。 + let capability: camera.CameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[this.cameraPosition], camera.SceneMode.NORMAL_PHOTO); + if (!capability) { + console.error('initCamera getSupportedOutputCapability'); + } + + let previewProfilesArray: Array = capability.previewProfiles; + if (!previewProfilesArray) { + console.error("createOutput previewProfilesArray == null || undefined"); + } + + let photoProfilesArray: Array = capability.photoProfiles; + if (!photoProfilesArray) { + console.error("createOutput photoProfilesArray == null || undefined"); + } + + // 预览 + let minRatioDiff: number = 0.1; + let surfaceRatio: number = this.imageWidth / this.imageHeight; // 最接近16:9宽高比。 + let previewProfile: camera.Profile = previewProfilesArray[0]; + + // // 应用开发者根据实际业务需求选择一个支持的预览流previewProfile。 + // for (let index = 0; index < previewProfilesArray.length; index++) { + // const tempProfile = previewProfilesArray[index]; + // let tempRatio = tempProfile.size.width >= tempProfile.size.height ? + // tempProfile.size.width / tempProfile.size.height : tempProfile.size.height / tempProfile.size.width; + // let currentRatio = Math.abs(tempRatio - surfaceRatio); + // if (currentRatio <= minRatioDiff && tempProfile.format == camera.CameraFormat.CAMERA_FORMAT_JPEG) { + // previewProfile = tempProfile; + // break; + // } + // } + // this.imageWidth = previewProfile.size.width; // 更新xComponent组件的宽。 + // this.imageHeight = previewProfile.size.height; // 更新xComponent组件的高。 + // console.info(`initCamera imageWidth:${this.imageWidth} imageHeight:${this.imageHeight}`); + + // 使用xComponentSurfaceId创建预览。 + this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.xComponentSurfaceId); + if (!this.previewOutput) { + console.error('initCamera createPreviewOutput'); + } + + // 拍照 + this.photoOutput = this.cameraManager.createPhotoOutput(photoProfilesArray[0]); + this.setPhotoOutputCb(this.photoOutput); + + // 创建录像模式相机会话。 + if(this.mode == 'video') { + this.videoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession; + if (!this.videoSession) { + console.error('initCamera createSession'); + } + // 开始配置会话。 + this.videoSession.beginConfig(); + // 添加相机设备输入。 + this.videoSession.addInput(this.cameraInput); + // 添加预览流输出。 + this.videoSession.addOutput(this.previewOutput); + // 提交会话配置。 + await this.videoSession.commitConfig(); + // 开始启动已配置的输入输出流。 + await this.videoSession.start(); + } else if(this.mode == 'photo') { + this.photoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession; + if (!this.photoSession) { + console.error('initCamera createSession'); + } + // 开始配置会话。 + this.photoSession.beginConfig(); + // 添加相机设备输入。 + this.photoSession.addInput(this.cameraInput); + // 添加预览流输出。 + this.photoSession.addOutput(this.previewOutput); + // 添加拍照输出流 + this.photoSession.addOutput(this.photoOutput); + // 提交会话配置。 + await this.photoSession.commitConfig(); + // 开始启动已配置的输入输出流。 + await this.photoSession.start(); + } + + } catch (error) { + console.error(`initCamera fail: ${error}`); + } + } + + // 释放相机。 + async releaseCamera(): Promise { + try { + if(this.mode == 'video') { + // 停止当前会话。 + await this.videoSession?.stop(); + // 释放相机输入流。 + await this.cameraInput?.close(); + // 释放预览输出流。 + await this.previewOutput?.release(); + // 释放会话。 + await this.videoSession?.release(); + } else if(this.mode == 'photo') { + // 停止当前会话。 + await this.photoSession?.stop(); + // 释放相机输入流。 + await this.cameraInput?.close(); + // 释放预览输出流。 + await this.previewOutput?.release(); + // 释放拍照输出流。 + await this.photoOutput?.release(); + // 释放会话。 + await this.photoSession?.release(); + } + } catch (error) { + console.error(`initCamera fail: ${error}`); + } + } + + setPhotoOutputCb(photoOutput: camera.PhotoOutput): void { + //设置回调之后,调用photoOutput的capture方法,就会将拍照的buffer回传到回调中。 + photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => { + if (errCode || photo === undefined) { + console.error('getPhoto failed'); + return; + } + let imageObj = photo.main; + imageObj.getComponent(image.ComponentType.JPEG, async (errCode: BusinessError, component: image.Component) => { + if (errCode || component === undefined) { + console.error('getComponent failed'); + return; + } + let buffer: ArrayBuffer; + if (component.byteBuffer) { + buffer = component.byteBuffer; + } else { + console.error('byteBuffer is null'); + return; + } + + // 生成照片 + try { + const tempDir = this.context?.cacheDir; + + const timestamp = new Date().getTime(); + const fileName = `photo_${timestamp}.jpg`; + const filePath = `${tempDir}/${fileName}`; + + const file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + await fs.write(file.fd, buffer); + await fs.close(file.fd); + + this.onTake?.(filePath); + + } catch (error) { + console.error('保存临时照片失败:', error); + } finally { + imageObj.release(); + } + }); + }); + } + + takePhoto() { + let photoCaptureSetting: camera.PhotoCaptureSetting = { + quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高。 + rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0。 + } + + // 使用当前拍照设置进行拍照。 + this.photoOutput?.capture(photoCaptureSetting, (err: BusinessError) => { + if (err) { + console.error(`Failed to capture the photo ${err.message}`); + return; + } + // console.info('Callback invoked to indicate the photo capture request success.'); + }); + } + + // 切换摄像头 + async switchCamera() { + if (this.cameras.length < 2) { + console.error('Only one camera available'); + return; + } + + // 切换摄像头位置 + this.cameraPosition = (this.isFrontCamera + ? camera.CameraPosition.CAMERA_POSITION_FRONT + : camera.CameraPosition.CAMERA_POSITION_BACK) - 1; + + await this.releaseCamera(); + await this.initCamera(); + } + + // 手电筒 + onTorch() { + try { + let torchSupport = this.cameraManager?.isTorchSupported() ?? false + if(torchSupport) { + if(this.cameraPosition == camera.CameraPosition.CAMERA_POSITION_BACK - 1) { + console.error('back camera not support'); + return + } + + this.cameraManager?.setTorchMode(this.isTorchOn ? camera.TorchMode.ON : camera.TorchMode.OFF); + } + } catch (error) { + console.error(error); + } + } + + // 闪光灯 + onFlash() { + try { + let torchSupport = this.cameraManager?.isTorchSupported() ?? false + if(torchSupport) { + if(this.cameraPosition == camera.CameraPosition.CAMERA_POSITION_FRONT - 1) { + console.error('front camera not support'); + return + } + + this.cameraManager?.setTorchMode(this.isFlashOn ? camera.TorchMode.AUTO : camera.TorchMode.OFF); + } + } catch (error) { + console.error(error); + } + } + + build() { + Column() { + if (this.isShow) { + XComponent({ + id: 'componentId', + type: XComponentType.SURFACE, + controller: this.xComponentCtl + }) + .onLoad(async () => { + // 获取组件surfaceId。 + this.xComponentSurfaceId = this.xComponentCtl.getXComponentSurfaceId(); + // 初始化相机,组件实时渲染每帧预览流数据。 + this.initCamera() + }) + .width(this.uiContext.px2vp(this.imageHeight)) + .height(this.uiContext.px2vp(this.imageWidth)) + } + } + .justifyContent(FlexAlign.Center) + .backgroundColor(Color.Black) + .height('100%') + .width('100%') + } +} + +@Builder +export function CameraView(params: ESObject) { + Row() { + CameraViewComponent({ + mode: 'photo', + isFront: params.isFront, + isFlash: params.isFlash, + isTorch: params.isTorch, + command: params.command, + correctOrientation: params.correctOrientation, + onTake: (path: string) => { + let fun = params.onTake as (path: string) => void + fun(path) + } + }) + .width('100%') + .height('100%') + } + .width('100%') + .height('100%') + .attributeModifier(params.attributeUpdater) +} \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-harmony/index.uts b/uni_modules/lime-camera/utssdk/app-harmony/index.uts new file mode 100644 index 0000000..7886094 Binary files /dev/null and b/uni_modules/lime-camera/utssdk/app-harmony/index.uts differ diff --git a/uni_modules/lime-camera/utssdk/app-harmony/module.json5 b/uni_modules/lime-camera/utssdk/app-harmony/module.json5 new file mode 100644 index 0000000..9524e2a --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-harmony/module.json5 @@ -0,0 +1,27 @@ +{ + "module": { + "name": "uni_modules__ux_camera_view_har", + "type": "har", + "deviceTypes": [ + "default", + "tablet", + "2in1" + ], + "requestPermissions": [ + { + "name": "ohos.permission.CAMERA", + "reason": "$string:permission_CAMERA_reason", + "usedScene": { + "when": "inuse" + } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:permission_MICROPHONE_reason", + "usedScene": { + "when": "inuse" + } + } + ] + } +} diff --git a/uni_modules/lime-camera/utssdk/app-harmony/resources/base/element/string.json b/uni_modules/lime-camera/utssdk/app-harmony/resources/base/element/string.json new file mode 100644 index 0000000..9fc3e41 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-harmony/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "permission_CAMERA_reason", + "value": "需要相机权限来实现拍摄功能" + }, + { + "name": "permission_MICROPHONE_reason", + "value": "需要录音权限来实现拍摄录音功能" + } + ] +} \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-ios/camera.uts b/uni_modules/lime-camera/utssdk/app-ios/camera.uts new file mode 100644 index 0000000..7844f29 Binary files /dev/null and b/uni_modules/lime-camera/utssdk/app-ios/camera.uts differ diff --git a/uni_modules/lime-camera/utssdk/app-ios/index.uts b/uni_modules/lime-camera/utssdk/app-ios/index.uts new file mode 100644 index 0000000..23900bb Binary files /dev/null and b/uni_modules/lime-camera/utssdk/app-ios/index.uts differ diff --git a/uni_modules/lime-camera/utssdk/app-ios/index.vue b/uni_modules/lime-camera/utssdk/app-ios/index.vue new file mode 100644 index 0000000..917ea64 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-ios/index.vue @@ -0,0 +1,266 @@ + + + + \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/app-ios/info.plist b/uni_modules/lime-camera/utssdk/app-ios/info.plist new file mode 100644 index 0000000..22ba602 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/app-ios/info.plist @@ -0,0 +1,14 @@ + + + + + NSCameraUsageDescription + 我们需要您的相机权限来拍照或录像。 + NSPhotoLibraryUsageDescription + 需要使用你的相册进行选择视频及图片 + NSPhotoLibraryAddUsageDescription + 需要保存图片和视频至你的相册中 + PHPhotoLibraryPreventAutomaticLimitedAccessAlert + 需要保存图片和视频至你的相册中 + + \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/interface.uts b/uni_modules/lime-camera/utssdk/interface.uts new file mode 100644 index 0000000..9699418 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/interface.uts @@ -0,0 +1,227 @@ +// #ifdef APP-ANDROID +import ImageProxy from 'androidx.camera.core.ImageProxy'; +// #endif + +export type GeneralCallbackResult = { + /** 错误信息 */ + errMsg : string +} +export type TakePhotoSuccessCallbackResult = { + /** 照片文件的临时路径 (本地路径),安卓是jpg图片格式,ios是png */ + tempImagePath : string + errMsg : string +} + +export type TakePhotoCallback = (res: string) => void + +/** 接口调用失败的回调函数 */ +export type TakePhotoFailCallback = (res : GeneralCallbackResult) => void +/** 接口调用成功的回调函数 */ +export type TakePhotoSuccessCallback = ( + result : TakePhotoSuccessCallbackResult +) => void + +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +export type TakePhotoCompleteCallback = (res : GeneralCallbackResult) => void + +export type TakePhotoOption = { + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: TakePhotoCompleteCallback + /** 接口调用失败的回调函数 */ + fail ?: TakePhotoFailCallback + /** 成像质量 + * + * 可选值: + * - 'high': 高质量; + * - 'normal': 普通质量; + * - 'low': 低质量; + * - 'original': 原图; */ + quality ?: 'high' | 'normal' | 'low' | 'original' + /** + * 是否开启镜像 */ + selfieMirror ?: boolean + /** 接口调用成功的回调函数 */ + success ?: TakePhotoSuccessCallback +} + + +export type SetZoomSuccessCallbackResult = { + /** 实际设置的缩放级别。由于系统限制,某些机型可能无法设置成指定值,会改用最接近的可设值。 */ + zoom : number + errMsg : string +} +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +export type SetZoomCompleteCallback = (res : GeneralCallbackResult) => void +/** 接口调用失败的回调函数 */ +export type SetZoomFailCallback = (res : GeneralCallbackResult) => void +/** 接口调用成功的回调函数 */ +export type CameraContextSetZoomSuccessCallback = ( + result : SetZoomSuccessCallbackResult +) => void + +export type CameraContextSetZoomOption = { + /** 缩放级别,范围[1, maxZoom]。zoom 可取小数,精确到小数后一位。maxZoom 可在 bindinitdone 返回值中获取。 */ + zoom : number + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: SetZoomCompleteCallback + /** 接口调用失败的回调函数 */ + fail ?: SetZoomFailCallback + /** 接口调用成功的回调函数 */ + success ?: CameraContextSetZoomSuccessCallback +} + +export type StartRecordTimeoutCallbackResult = { + /** 封面图片文件的临时路径 (本地路径) */ + tempThumbPath : string + /** 视频的文件的临时路径 (本地路径) */ + tempVideoPath : string +} + +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +export type StartRecordCompleteCallback = (res : GeneralCallbackResult) => void +/** 接口调用失败的回调函数 */ +export type StartRecordFailCallback = (res : GeneralCallbackResult) => void +/** 超过录制时长上限时会结束录像并触发此回调,录像异常退出时也会触发此回调 */ +export type StartRecordTimeoutCallback = ( + result : StartRecordTimeoutCallbackResult +) => void +/** 接口调用成功的回调函数 */ +export type CameraContextStartRecordSuccessCallback = ( + res : GeneralCallbackResult +) => void +export type CameraContextStartRecordOption = { + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: StartRecordCompleteCallback + /** 接口调用失败的回调函数 */ + fail ?: StartRecordFailCallback + /** + * 是否开启镜像 */ + selfieMirror ?: boolean + /** 接口调用成功的回调函数 */ + success ?: CameraContextStartRecordSuccessCallback + /** + * 录制时长上限,单位为秒,最长不能超过 5 分钟 */ + timeout ?: number + /** 超过录制时长上限时会结束录像并触发此回调,录像异常退出时也会触发此回调 */ + timeoutCallback ?: StartRecordTimeoutCallback +} + +export type StopRecordSuccessCallbackResult = { + /** 封面图片文件的临时路径 (本地路径) */ + tempThumbPath : string + /** 视频的文件的临时路径 (本地路径) */ + tempVideoPath : string + errMsg : string +} +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +export type StopRecordCompleteCallback = (res : GeneralCallbackResult) => void +/** 接口调用失败的回调函数 */ +export type StopRecordFailCallback = (res : GeneralCallbackResult) => void +/** 接口调用成功的回调函数 */ +export type CameraContextStopRecordSuccessCallback = ( + result : StopRecordSuccessCallbackResult +) => void +export type CameraContextStopRecordOption = { + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: StopRecordCompleteCallback + /** 启动视频压缩,压缩效果同`chooseVideo` */ + compressed ?: boolean + /** 接口调用失败的回调函数 */ + fail ?: StopRecordFailCallback + /** 接口调用成功的回调函数 */ + success ?: CameraContextStopRecordSuccessCallback +} + +/** 回调函数 */ +export type OnCameraFrameCallback = (result : OnCameraFrameCallbackResult) => void +export type OnCameraFrameCallbackResult = { + /** 图像像素点数据,一维数组,每四项表示一个像素点的 rgba */ + // #ifdef APP-ANDROID + data : ImageProxy + // #endif + // #ifndef APP-ANDROID + data : ArrayBuffer + // #endif + /** 图像数据矩形的高度 */ + height : number + /** 图像数据矩形的宽度 */ + width : number +} +/** 接口调用成功的回调函数 */ +export type StartSuccessCallback = (res : GeneralCallbackResult) => void +/** 接口调用失败的回调函数 */ +type StartFailCallback = (res : GeneralCallbackResult) => void +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +type StartCompleteCallback = (res : GeneralCallbackResult) => void +export type CameraFrameListenerStartOption = { + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: StartCompleteCallback + /** 接口调用失败的回调函数 */ + fail ?: StartFailCallback + /** 接口调用成功的回调函数 */ + success ?: StartSuccessCallback + /** [Worker](https://developers.weixin.qq.com/miniprogram/dev/api/worker/Worker.html) + * + * 可选参数。如果需要在 iOS ExperimentalWorker 内监听摄像头帧数据,则需要传入对应 Worker 对象。详情 [Worker.getCameraFrameData](https://developers.weixin.qq.com/miniprogram/dev/api/worker/Worker.getCameraFrameData.html) */ + // worker ?: Worker +} + + +/** 接口调用结束的回调函数(调用成功、失败都会执行) */ +export type StopCompleteCallback = (res : GeneralCallbackResult) => void +/** 接口调用失败的回调函数 */ +export type StopFailCallback = (res : GeneralCallbackResult) => void +/** 接口调用成功的回调函数 */ +export type StopSuccessCallback = (res : GeneralCallbackResult) => void +export type StopOption = { + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete ?: StopCompleteCallback + /** 接口调用失败的回调函数 */ + fail ?: StopFailCallback + /** 接口调用成功的回调函数 */ + success ?: StopSuccessCallback +} + +// export type CameraFrameListener = { +// /** +// * 开始监听帧数据 */ +// start(option ?: CameraFrameListenerStartOption) : void +// /** +// * 停止监听帧数据 */ +// stop(option ?: StopOption) : void +// } + +export type FlashMode = 'auto' | 'on' | 'off' | 'torch' +export type DevicePosition = 'back' | 'front' +export type Resolution = 'low' | 'medium' | 'high' +export type FrameSize = 'medium' | 'small' | 'large' +// type OutputDimension = '360P' | '540P' | '720P' | '1080P' | 'max' +export type QualityType = 'high' | 'normal' | 'low' | 'original' + + +export type CameraConfig = { + flash ?: FlashMode + devicePosition ?: DevicePosition + resolution ?: Resolution + frameSize ?: FrameSize + focus ?: boolean + // outputDimension ?: OutputDimension +} + + +export interface CameraFrameListener { + start():void + start(option ?: CameraFrameListenerStartOption):void + stop():void + stop(option ?: StopOption):void +} + + +export interface CameraContext { + takePhoto(option : TakePhotoOption):void + setZoom(option : CameraContextSetZoomOption):void + startRecord(option : CameraContextStartRecordOption):void + stopRecord(option : CameraContextStopRecordOption) :void + onCameraFrame():CameraFrameListener + onCameraFrame(callback : OnCameraFrameCallback | null) : CameraFrameListener +} \ No newline at end of file diff --git a/uni_modules/lime-camera/utssdk/web/index.uts b/uni_modules/lime-camera/utssdk/web/index.uts new file mode 100644 index 0000000..e514a0e Binary files /dev/null and b/uni_modules/lime-camera/utssdk/web/index.uts differ diff --git a/uni_modules/lime-camera/utssdk/web/index.vue b/uni_modules/lime-camera/utssdk/web/index.vue new file mode 100644 index 0000000..8e1ecd8 --- /dev/null +++ b/uni_modules/lime-camera/utssdk/web/index.vue @@ -0,0 +1,71 @@ + + + + + \ No newline at end of file