374 lines
20 KiB
Markdown
374 lines
20 KiB
Markdown
# 原生自定义相机拍照、视频录制 (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
|
||
// 拍摄照片和视频时需要
|
||
<uses-permission android:name="android.permission.CAMERA" />
|
||
// 拍摄视频时需要Audio.ON(默认)
|
||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||
// 读取拍照、录像文件文件时需要
|
||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||
// 报错拍照、录像文件文件时需要(默认保存到沙盒缓存)
|
||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||
// 震动权限
|
||
<uses-permission android:name="android.permission.VIBRATE" />
|
||
```
|
||
|
||
## 快门声音素材
|
||
|
||
- 将需要的快门声音放在`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
|
||
<template>
|
||
<view class="ima-camera" :style="{ width: windowWidth, height: windowHeight }">
|
||
<ima-camera-view
|
||
ref="cameraRef"
|
||
class="camera-view"
|
||
:style="{ width: windowWidth + 'px', height: windowHeight + 'px' }"
|
||
flash="on"
|
||
@onPictureTaken="onPictureTaken"
|
||
onFocusStart="onFocusStart"
|
||
/>
|
||
<view class="camera-menu">
|
||
<!--返回键-->
|
||
<cover-image @tap="back" class="camera-menu-button back" src="/static/camera/back.png" />
|
||
<!--快门键-->
|
||
<cover-image
|
||
@tap="takePhoto"
|
||
class="camera-menu-button shutter"
|
||
src="/static/camera/shutter.png"
|
||
/>
|
||
<!--反转键-->
|
||
<cover-image @tap="flip" class="camera-menu-button flip" src="/static/camera/flip.png" />
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
let _this = null
|
||
export default {
|
||
data() {
|
||
return {
|
||
windowWidth: '', //屏幕可用宽度
|
||
windowHeight: '', //屏幕可用高度
|
||
facing: 'back'
|
||
}
|
||
},
|
||
onLoad() {
|
||
_this = this
|
||
this.initCamera()
|
||
},
|
||
methods: {
|
||
//初始化相机
|
||
initCamera() {
|
||
console.log('初始化相机')
|
||
uni.getSystemInfo({
|
||
success: (res) => {
|
||
_this.windowWidth = res.windowWidth
|
||
_this.windowHeight = res.windowHeight
|
||
}
|
||
})
|
||
},
|
||
onFocusStart(e) {
|
||
console.log('聚焦', e)
|
||
},
|
||
takePhoto() {
|
||
console.log('拍照', this.facing)
|
||
this.$refs.cameraRef.takePhoto()
|
||
},
|
||
//返回
|
||
back() {
|
||
console.log('返回上一页', this.facing)
|
||
uni.navigateBack()
|
||
},
|
||
//反转
|
||
flip() {
|
||
console.log('镜头反转', this.facing)
|
||
this.facing = this.facing === 'back' ? 'front' : 'back'
|
||
this.$refs.cameraRef.changeFacing(this.facing)
|
||
},
|
||
onPictureTaken(e) {
|
||
console.log('拍照结果', e.detail)
|
||
_this.snapshotsrc = e.detail?.path || ''
|
||
_this.getTakenRes()
|
||
uni.navigateBack()
|
||
},
|
||
//设置
|
||
getTakenRes() {
|
||
console.log('返回结果给上一页')
|
||
let pages = getCurrentPages()
|
||
let prevPage = pages[pages.length - 2] //上一个页面
|
||
//直接调用上一个页面的setImage()方法,把数据存到上一个页面中去
|
||
prevPage.$vm.setImage({ path: _this.snapshotsrc })
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.ima-camera {
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
.camera-view {
|
||
width: 100%;
|
||
background: #111;
|
||
}
|
||
|
||
.camera-menu {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 750rpx;
|
||
height: 180rpx;
|
||
z-index: 98;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&-button {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
position: absolute;
|
||
bottom: 50rpx;
|
||
z-index: 99;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.back {
|
||
left: 30rpx;
|
||
}
|
||
|
||
.shutter {
|
||
width: 130rpx;
|
||
height: 130rpx;
|
||
left: 310rpx;
|
||
bottom: 25rpx;
|
||
}
|
||
|
||
.flip {
|
||
right: 30rpx;
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
```
|
||
|
||
## 外接摄像头方向修正(Android)
|
||
|
||
适用于**无内置摄像头**或外接 USB 摄像头的设备(如横屏平板、工控一体机)。当物理安装的摄像头与屏幕方向不一致,导致预览画面旋转 90° 等情况时,可通过 `previewRotation` 固定修正预览与拍照方向。
|
||
|
||
### 使用方式
|
||
|
||
**方式一:属性(推荐)**
|
||
|
||
```nvue
|
||
<ima-camera-view
|
||
ref="cameraRef"
|
||
:previewRotation="90"
|
||
:previewCornerRadiusRate="0.5"
|
||
facing="front"
|
||
/>
|
||
```
|
||
|
||
**方式二:方法动态调整**
|
||
|
||
```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` |
|
||
|