更新记录
8.5.0(2022-09-23)
自定义水印功能
平台兼容性
Android | Android CPU类型 | iOS |
---|---|---|
适用版本区间:5.0 - 12.0 | armeabi-v7a:未测试,arm64-v8a:未测试,x86:未测试 | 适用版本区间:9 - 15 |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
- 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
- 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
- 开发完毕后正式云打包
付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios
注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择
camera-view-plus
温馨提示:可下载demo示例工程(Android/IOS 包名/BundleId: net.luanqing.camerademo)
为满足开发者不同的界面UI需求,更加自由搭建页面效果,本插件仅提供预览页面(不含任何按钮文字等) + API功能(拍照、录像、切换摄像头、闪光灯、水印设置),详情可参阅示例工程。如有未满足的功能亦可联系我们进行功能升级和优化
QQ: 835588741/1660584265 微信: 15921627041
注意
支持IOS/Android两大平台,只需要将插件加入到页面,然后云打包或打包自定义基座(注意:原生插件必须要在nvue的页面,nvue和vue基本功能一直,只是存在一些差异,比如css的用法等),即可调用开放的API接口(拍照、录像、闪光灯开关、前后摄像头镜像切换、水印logo设置),插件本身为满足用户的不同UI设计,仅提供预览+开放API,让插件实现高度自由的界面自定义,用户可自行在预览界面上叠加放置其他按钮或文字(具体可参照demo项目)。
关于水印,如果用户不希望拍摄的照片上有水印,可以不传或者调用addWaterText({})具体设置空值,视频的水印分为标签水印和背景防盗水印,标签水印也是通过addWaterText生成,背景水印则是在stopRecord停止录像时传值控制(默认无水印)
缺陷:在android平台端小部分机型存在拍照后旋转角度的问题 !!!
API 简要说明
名称 | 说明 | 默认值 | 是否必须 |
---|---|---|---|
resolutionRatio | 分辨率XS/S/M/L/XL/XXL | M | 非 |
addWaterText(...) | 水印内容({}),详情查看下方水印属性表 | 无 | 非 |
takePhoto() | 执行拍照 | 无 | 非 |
startRecord() | 开始录像 | 无 | 非 |
stopRecord({logoText,logoSize}) | 停止录像,可选传视频背景水印文字和字号 | 无 | 非 |
openFront() | 打开前置摄像头 | 无 | 非 |
openBack() | 打开后置摄像头 | 无 | 非 |
openFlash() | 打开闪光灯 | 无 | 非 |
closeFlash() | 关闭闪光灯 | 无 | 非 |
defaultCamera | 初始化的默认摄像头 | 后置摄像头 | 非 |
isSaveImage2Album | 是否保存到相册(相册可见) "0"否 "1"是 | 0否 | 非 |
isSaveVideo2Album | 是否保存到相册(相册可见) "0"否 "1"是 | 0否 | 非 |
@receiveRatio | 可接收到android最优宽高比 | 无 | 非 |
@onTakePhotoSuccess | 接受拍照成功的通知 | 无 | 非 |
@recordSuccess | 接收录像成功的通知 | 无 | 非 |
@receiveInfo | 接收反馈的一些异常报错信息 | 无 | 非 |
@onVideoSaveSuccess | 接收录制后视频保存成功通知 | 无 | 非 |
@onImageSaveSuccess | 接收拍照后图片保存成功通知 | 无 | 非 |
@restartPreview | 重新预览(谨慎使用,会影响性能) | 无 | 非 |
@onVideoWaterMarkProgress | 视频水印处理进度 | 无 | 非 |
特别注意: 1、@restartPreview方法:因为有部分特定机型反复切换到摄像头页面,有概率会造成摄像头黑屏,可在onShow方法里调用此函数,但会牺牲一部分性能 2、水印添加(分为视频水印和照片水印, mode=0时为照片水印,缺省或其他任意mode值为视频水印,视频水印可以设置多个)
API addWaterText 水印方法属性说明
名称 | 类型 | 说明 | 是否必须 |
---|---|---|---|
mode | Number | 水印类型,0或不传是图片水印,>0是视频水印,默认0 | 非 |
tag | String | 视频水印标签文字 | 非 |
x | Number | 视频水印标签x坐标 | 非 |
y | Number | 视频水印标签y坐标 | 非 |
tagSize | Number | 视频水印标签文字尺寸 | 非 |
tagAlpha | Number | 视频水印标签透明度0-255 | 非 |
tagBorderAlpha | Number | 视频水印标签边框透明度0-255 | 非 |
tagColor | String | 视频水印标签文字颜色,十六进制字符串 | 非 |
tagBorderColor | String | 视频水印标签边框颜色,十六进制字符串 | 非 |
unShowControl | Boolean | 视频水印标签是否不显示拉伸和缩放小按钮,默认显示 | 非 |
address | String | 图片水印的地址 | 非 |
date | String | 图片水印的日期 | 非 |
time | String | 图片水印的时间 | 非 |
weekday | String | 图片水印的星期 | 非 |
remark | String | 图片水印的备注 | 非 |
weather | String | 图片水印的天气 | 非 |
logo | String | 图片水印的文字品牌logo | 非 |
logoMarginRight | Number | logo的右边距 | 非 |
logoMarginBottom | Number | logo的底边距 | 非 |
customImgLogo | Object | 自定义图片Logo,详细见下表,Android端独有 | 非 |
customImgLogo 自定义图片logo属性说明
名称 | 类型 | 说明 | 是否必须 |
---|---|---|---|
url | String | 自定义图片logo的地址,不支持网络地址,如是_doc/的路径需转换成绝对路径 | |
sampleSize | Number | 压缩logo图片,如: 传2即 1/2,尺寸将是原图的50%,传4即是原图的25%,如大图可减少内存消耗 | 非 |
left | Number | logo图片距离屏幕左边的距离 | 非 |
top | Number | logo图片距离屏幕顶部的距离,left和top不填默认底部居中 | 非 |
width | Number | logo图片的宽度,不填默认是原图宽度 | 非 |
height | Number | logo图片的高度,不填默认是原图高度 | 非 |
offsetBottom | Number | logo图片的底部偏移量,如100则logo距离底部100 | 非 |
rotate | Number | logo图片的旋转角度,默认0不旋转 | 非 |
reversalX | Boolean | logo图片水平翻转 | 非 |
reversalY | Boolean | logo图片垂直翻转 | 非 |
特别注意:插件默认不会将图片、视频存入媒体库相册,如果需要在拍照录像后保存到相册请设置 isSaveImage2Album & isSaveVideo2Album ["0"不存相册 / "1"存入相册]
水印使用方法:
<!-- 用法简述 其他方法请参考文档 -->
<!-- 添加照片水印 此方法必须在拍照之前调用,否则水印不生效 -->
this.$refs.cameraObj.addWaterText({
"date":this.tempDateStr || "", // 日期
"logo":"· 七彩云 ·|水印相机", // 品牌文字logo
"address":(this.showAddress ? this.address:""),
"time":this.tempTimeStr || "", // 时间
"week":this.weekDay || "", // 星期
"remark":(this.showRemark ? this.remark:""), // 备注
"weather":"", // 天气描述
"logoMarginRight": 10, // 默认 0 logo距离屏幕右边的间距 logo默认在右下角
"logoMarginBottom" 35, // 默认 15 logo距离屏幕底部的间距 logo默认在右下角
“logoSpace”: 0 // 默认0 logo图片和文字的间距
”customImgLogo“: {url: 'xxxx'} // 自定义图片
});
// 通过下载的图片设置自定义logo图
uni.downloadFile({
url:'http://imgs.yisanguo.net/icons/icon_sys_mes_avatar.png',
success(res) {
// 需要转成绝对地址路径
let real = plus.io.convertLocalFileSystemURL(res.tempFilePath);
// 设置水印
$that.$refs.cameraObj.addWaterText({
"logo":"·七彩云·|水印相机",
"customImgLogo": {url:real}
});
$that.$refs.cameraObj.takePhoto();
}
})
<!-- 添加视频水印标签 tag标签名字必填 x/y 未填则默认初始居中 tagAlpha|标签文字透明度 tagColor|标签文字颜色 注意颜色值前面不要加#号-->
this.$refs.cameraObj.addWaterText({
"mode": 1, // 视频水印的标志, 0(或不传)是图片水印,>0都是视频水印
"unShowControl": true, // 是否显示缩放拉伸按钮的控制视图
"tag":"上海市·嘉定区 晴 39°", // 水印标签文字
"x": 100, // 水印标签的x坐标
"y": 200, // 水印标签的y坐标
"tagAlpha": 120, // 水印标签的透明度 0 - 255
"tagColor":"FFFFFF", // 水印标签的颜色
});
<!-- 停止录像 并设置防盗背景水印 -->
this.$refs.cameraObj.stopRecord({logoText:'上海栾青网络科技有限公司',logoSize:46});
// 上传函数
testUpload(filePath){
const $that = this;
// 改为各位大神自己的服务器上传接口地址
const urlPath = "https://.../.../...";
const uploadTask = uni.uploadFile({
url: urlPath, // 仅为示例,非真实的接口地址
filePath: filePath,
name: 'file',
timeout:300 * 1000, // 五分钟超时
header: {
'Content-Type': 'application/json; charset=UTF-8', // 默认值
'Source-Type': 'WEB',
'Accept': '*/*',
},
success: (uploadFileRes) => {
console.log("上传成功:",uploadFileRes.data);
},
fail: (e)=>{
console.error("上传失败",e);
}
});
},
<!-- 注意:如果需要精确的宽高,请自行计算定义宽高并更改,上述代码示例中为了方便固定了750 1200 -->
对于需要上传的开发者,可在拍照/录像完成后在回调方法里得到照片/视频的保存路径,然后调用上传接口上传即可
开发者监听回调能得到哪些数据
回调的数据格式 receiveInfo:
{
detail:{
code:2003,
message:'用户未授权',
ratio:0.75 // 仅android端返回 此参数为android设备摄像头最优的宽高比例
videoPath:'......', // 根据平台系统不同
imagePath:'.......' // 根据平台系统不同
isSaveImage2Album: ? // 是否保存图片到相册 用户可以在相册中看到照片
isSaveVideo2Album: ? // 是否保存视频到相册 用户可以在相册中看到视频
progress: // 视频水印处理进度 回调@onVideoWaterMarkProgress时生效
}
}
code状态码:
200成功 2001拍照失败 2002录像失败 2003缺少权限 2004图片保存失败 2005|SD卡不可用,图片保存失败 2006视频处理状态码
视频示例代码
<template>
<!-- add by xushiyong 创建nvue页面用来承载camera原生插件 -->
<!-- nvue (native vue) 即原生渲染方式,效率和行囊更高,但在css方面存在存在差异和不足 -->
<!-- nvue默认flex布局,不需要再额外指明 -->
<!-- 无法使用百分比和calc计算函数,750rpx默认是屏宽, 也可以使用flex:1来指定 -->
<view class="window" :style="'flex:1'">
<camera-view
mode=2
ref="cameraObj"
class="camera_view"
:defaultCamera="currentCamera"
resolutionRatio="M"
isSaveImage2Album="0"
isSaveVideo2Album="0"
@onTakePhotoSuccess="takePhotoSuccess"
@onTakePhotoFail="takePhotoFail"
@recordSuccess="recordSuccess"
@recordFail="recordFail"
@onVideoSaveSuccess="onSaveVideoSuccess"
@=""
@onVideoWaterMarkProgress="onVideoWaterMarkProgress"
:style="'width:'+750+'rpx;flex:1'"
>
<!-- :style="'width:'+750+'rpx;flex:1'" -->
</camera-view>
<view v-if="tip" class="top_tip_view">{{tip}}</view>
<view class="root_layout">
<view class="func_align_bottom" style="display: flex;flex-direction: row;justify-content: space-between;flex: 1;">
<view class="flex_row flex_align_center flex1 marbot130rpx" @click="addVideoWaterText">
<image src="../../../static/icon/icon_video_back.png" class="tip_play_icon"></image>
<text class="text_white fontSize16px marginLeft10px">添加水印</text>
</view>
<view class="ovay_white flex_align_center marbot50rpx" v-if="!this.isRecord">
<view class="ovay_red flex_align_center" @click="doControlRecord">
<text class="text_white fontSize16px text_weight">开始</text>
<text class="text_white fontSize16px text_weight">录制</text>
</view>
</view>
<view class="ovay_white flex_align_center marbot50rpx" v-else>
<view class="ovay_gray flex_align_center" @click="doControlRecord">
<text class="fontSize16px text_weight">{{curSecond}}s</text>
<text class="fontSize16px text_weight">停止</text>
</view>
</view>
<view class="flex_row flex_align_center flex1 marbot130rpx" @click="switchCamera">
<image src="../../../static/icon/icon_video_switch.png" class="tip_play_icon"></image>
<text class="text_white fontSize16px marginLeft10px">切换镜头</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data(){
return{
tip:undefined,
curSecond:25,
maxSecond:25,
intervalObj:undefined,
isRecord:false,
currentCamera:"0" // "0"后置 "1"前置
}
},
methods:{
// 处理视频水印时的进度回调
onVideoWaterMarkProgress(e){
console.error("视频处理中:",e);
this.tip = '视频处理中,当前进度:'+(e?.detail?.progress);
const $that = this;
if(e?.detail?.progress >= 99){
$that.tip = "视频水印添加已完成(查看日志获取保存路径)";
setTimeout(()=>{
if($that && $that.tip){
$that.tip = undefined;
}
}, 3000)
}
},
onSaveVideoSuccess(e){
console.error("视频保存成功!",e);
},
// 开始和停止录制
doControlRecord(){
console.error("录制控制器");
if(this.isRecord){
if(this.curSecond >= 20){
uni.showToast({
title:'拍摄视频不能短于5秒',
icon:'none'
})
return ;
}
if(this.intervalObj){
clearInterval(this.intervalObj);
}
this.isRecord = false;
this.$refs.cameraObj.stopRecord();
}else{
this.isRecord = true;
this.startTimeCount();
this.$refs.cameraObj.startRecord();
}
},
// 添加视频水印(mode > 0 时为视频水印,==0 时为照片水印)
// unShowControl是视频水印的边框和拉伸、旋转提示按钮
addVideoWaterText(){
console.error("添加水印start");
this.$refs.cameraObj.addWaterText({
"mode":1,
"unShowControl": true,
"tag":"视频文字水印",
"x": 100,
"y": 200,
"tagSize":"m",
"tagAlpha": 120,
"tagColor":"FFFFFF",
});
console.error("添加水印end");
},
// 启动计时器
startTimeCount(){
const $that = this;
$that.curSecond = $that.maxSecond;
if($that.intervalObj){
clearInterval($that.intervalObj);
}
$that.intervalObj = setInterval(()=>{
// console.error("定时器",$that.curSecond);
if($that.curSecond > 0){
$that.curSecond -= 1;
}
if($that.curSecond <= 0){
if($that.intervalObj){
$that.doControlRecord();
clearInterval($that.intervalObj);
}
}
},1000);
},
recordSuccess(e){
console.error("视频录制成功:",e);
},
recordFail(e){
console.error("视频录制失败:",e);
},
// 切换前后摄像头
switchCamera(){
if(this.currentCamera === "0"){
this.currentCamera = "1";
this.$refs.cameraObj.openFront();
}else{
this.currentCamera = "0";
this.$refs.cameraObj.openBack();
}
}
}
}
</script>
<style>
.func_align_bottom{
align-items: flex-end;
}
.marbot50rpx{
margin-bottom: 100rpx;
}
.marbot130rpx{
margin-bottom: 160rpx;
}
.flex_row{
display: flex;
flex-direction: row;
}
.flex_align_center{
align-items: center;
justify-content: center;
}
.window{
background-color: black;
width: 750rpx;
position: relative;
/* position: relative; */
}
.root_layout{
position: absolute;
width: 750rpx;
top: 0rpx;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 50;
/* position: relative; */
}
.camera_view{
position: absolute;
top: 0rpx;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 100;
}
.tip_layout{
top: 100rpx;
left: 0rpx;
right: 0rpx;
/* margin-top: 100rpx; */
}
.func_layout{
bottom: 80rpx;
left: 0rpx;
right: 0rpx;
}
.tip_text{
top: 180rpx;
}
.tip_bg{
background-color: #E00300;
border-radius: 50rpx;
padding-top: 14rpx;
padding-bottom: 14rpx;
}
.tip_play_icon{
width: 40rpx;
height: 40rpx;
}
.top_tip_view{
position: fixed;
top: 0;
left: 0;
right: 0;
height: 50rpx;
color: #ffffff;
background-color: #E00300;
font-size: 28rpx;
}
.bg_image{
width: 750rpx;
height: 1280rpx;
}
.tip1{
color: #E00300;
}
.ovay_white{
width: 165rpx;
height: 165rpx;
background-color: white;
/* border: 8rpx solid white; */
border-radius: 100rpx;
}
.ovay_red{
border: 6rpx solid black;
background-color: #E00300;
width: 150rpx;
height: 150rpx;
border-radius: 100rpx;
}
.ovay_red:active{
background-color: #CCC;
border: 6rpx solid red;
}
.ovay_gray{
color: #777;
border: 6rpx solid #BBB;
background-color: #F6F6F6;
width: 150rpx;
height: 150rpx;
border-radius: 100rpx;
}
.ovay_gray:active{
background-color: #E00300;
border: 6rpx solid red;
}
.stop_icon{
background-color: black;
border-radius: 10rpx;
width: 45rpx;
height: 45rpx;
}
</style>
相机示例代码
<template>
<view class="window">
<view class="camera_layout">
<!-- :style="'width:'+previewWidth+'px;height:'+previewHeight+'px;margin-left:-'+marginLeft+'px'" -->
<!-- 相机原生插件 START -->
<camera-view
ref="cameraObj"
class="camera_view"
:class="previewSizeStyle"
isSaveImage2Album="1"
isSaveVideo2Album="1"
:defaultCamera="currentCamera"
@receiveRatio="receiveRatio"
@takePhotoSuccess="takePhotoSuccess"
@recordSuccess="recordSuccess"
@recordFail="recordFail"
@receiveInfo="receiveInfo"
@onVideoSaveSuccess="onVideoSaveSuccess"
@onImageSaveSuccess="onImageSaveSuccess"
>
</camera-view>
<!-- 相机原生插件 END -->
<!-- 倒计时START -->
<!-- :style="'width:'+previewWidth+'px;height:'+previewHeight+'px;'" -->
<view class="delay_time_layout" :class="previewSizeStyle">
<text class="delay_time_text_size" v-if="delayTakePhotoTime>0">{{delayTakePhotoTime}}</text>
</view>
<!-- 倒计时END -->
<!-- 水印布局 START -->
<!-- :style="'width:'+previewWidth+'px;height:'+previewHeight+'px;'" -->
<view class="water_layout" :class="previewSizeStyle">
<view class="demo_flex_row marginLeft10px" @click.stop="gotoWaterSetting">
<!-- <uni-dateformat format="hh:mm" :date="currentDate" class="text_white text_weight fontSize30px"></uni-dateformat> -->
<text class="text_white text_weight px40">{{timeStr}}</text>
<view class="water_text_line marginLeft15px"></view>
<view class="marginLeft5px">
<!-- <uni-dateformat format="yyyy-MM-dd" :date="currentDate" class="text_white fontSize14px"></uni-dateformat> -->
<text class="text_white px14">{{dateStr}}</text>
<text class="text_white px14">{{weekDay}}</text>
</view>
</view>
<text class="text_white px14 marginLeft10px marginBottom5px" @click.stop="gotoWaterSetting" v-if="showAddress">{{address}}</text>
<text class="text_white px14 marginLeft10px marginBottom10px" @click.stop="gotoWaterSetting" :style="'width:'+(previewWidth/2)+'rpx'" v-if="remark && showRemark">{{remark}}</text>
<!-- <text class="text_white px14 marginLeft10px marginBottom10px" @click.stop="gotoWaterSetting" :style="'width:'+(previewWidth/2)+'rpx'" v-if="remark && showRemark">备注:{{remark}}</text> -->
<!-- <view style="height: 10px;"></view> -->
</view>
<!-- 水印布局 END -->
<view class="water_text_location flex_align_center" @click.stop="gotoResetLocation">
<image class="water_text_location_icon" src="../../../static/icon/icon_location.png"></image>
<text class="text_white px14 marginTop5px">重新定位</text>
</view>
</view>
<!-- <view class="camera_top_bar"></view> -->
<!-- <view class="root_layout"> -->
<!-- 顶部操作栏 START -->
<view class="camera_top_bar">
<view class="demo_flex_row">
<uni-icons type="back" @click="doBackPage" size="25"></uni-icons>
<!-- <image src="../../../static/icon/icon_back.png" class="icon_size marginLeft10px" @click="doBackPage"></image> -->
</view>
<view class="demo_flex_row">
<!-- <text class="ratio_view" v-if="previewRatio === 1" @click="switchPriviewRatio">1 : 1</text>
<text class="ratio_view" v-if="previewRatio === 2" @click="switchPriviewRatio">4 : 3</text>
<text class="ratio_view" v-if="previewRatio === 3" @click="switchPriviewRatio">16 : 9</text>
-->
<!-- 闪光灯的开关 -->
<image :src="flashStatus === 0 ? '../../../static/icon/icon_flash_close.png':'../../../static/icon/icon_flash_open.png'" class="icon_size marginRight20px" @click="switchFlash"></image>
<!-- 延时拍摄 -->
<image src="../../../static/icon/icon_delay_take_photo.png" class="icon_size marginRight20px" @click="delayTakePhoto(5)"></image>
<!-- 切换摄像头 -->
<image src="../../../static/icon/icon_camera_switch.png" class="icon_size2 marginRight20px" @click="switchCamera"></image>
</view>
</view>
<!-- 顶部操作栏 START -->
<!-- <view class="flex1"></view> -->
<!-- 底部操作栏 START-->
<view class="demo_flex_row take_photo_layout">
<!-- <image style="width: 60rpx;height: 60rpx;"></image> -->
<view class="ovay_red demo_flex_row">
<text class="ovay_red_border" @click="takePhoto"></text>
</view>
<!-- <view></view> -->
</view>
<!-- 底部操作栏 END-->
<!-- </view> -->
</view>
</template>
<script>
export default {
data() {
return {
// 1|1:1 2|4:3 3|16:9
flashStatus:0, // 闪光灯,默认关闭
delayTakePhotoTime:0, // 拍摄的剩余延时
delayTakePhotoInterval:undefined, // 定时器的对象
dateTimeInterval:undefined,
currentCamera:'0', // 当前摄像头 0|后置 1|前置
currentDate: new Date().getTime(),
timeStr:'',
dateStr:'',
weekDay:'',
remark:'',
// 临时存储按压快门时的时间,因为每隔2秒会递增,用来记录可能会存在时间差
tempTimeStr:'',
tempDateStr:'',
showRemark:false,
showAddress:true,
takePhotoBtnMarginBottom:200, // 拍照按钮距离底部的边距值
previewRatio: 2,
previewWidth:0,
previewHeight:851,
screenHeight:0,
screenWidth:0,
marginLeft:0,
cameraRatio:0.75,
address:'',
latitude:0,
longitude:0,
previewSizeStyle:'design_size4_3',
}
},
() {
// previewRatio
const sys = uni.getSystemInfoSync();
this.previewWidth = sys.screenWidth;
this.previewHeight = sys.screenHeight;
this.screenHeight = sys.screenHeight;
this.screenWidth = sys.screenWidth;
this.calcPreviewSize();
// once注册后只接受一次,因为不需要额外多次接受,而且也可避免忘记移除
uni.$once("receiveWaterInfo",this.receiveWaterInfo);
uni.$once("receivePoi",this.receivePoi);
console.error("宽度:"+this.screenWidth+" 高度:"+this.screenHeight)
// console.error("哈哈哈")
// // 计算出来预览页面的分辨率尺寸 START
// const sys = uni.getSystemInfoSync();
// this.previewWidth = sys.screenWidth;
// this.previewHeight = sys.screenHeight;
// this.screenHeight = sys.screenHeight;
// this.screenWidth = sys.screenWidth;
// console.error("哈哈哈1")
// let tempWidth = this.previewWidth * 1.20;
// let tempHeight = tempWidth / 0.7;
// let heightDiff = this.previewHeight - tempHeight;
// // 如果屏幕高度仍大于计算出来的适配高度,就需要重新计算
// if(heightDiff > 0){
// tempHeight = tempHeight + heightDiff * 2;
// tempWidth = tempHeight * 0.7;
// };
// console.error("哈哈哈2")
// this.previewWidth = tempWidth;
// this.previewHeight = tempHeight;
// this.marginLeft = (this.previewWidth / 2 - this.screenWidth / 2);
// console.error("哈哈哈4")
// 0.7 的宽高比
// 计算出来预览页面的分辨率尺寸 END
// this.currentDate = new Date().getTime();
// console.error("当前时间:",new Date());
this.currentDate = new Date().getTime();
this.dateStr = this.getNowDate(this.currentDate);
this.timeStr = this.getNowTime(this.currentDate);
if(!this.address){
this.getLocation();
}
this.startTimeCount();
this.getWeekDay();
},
onHide() {
if(this.dateTimeInterval)
clearInterval(this.dateTimeInterval);
},
methods: {
receiveInfo(e){
console.error("接收到报告:",e);
},
recordFail(e){
},
recordSuccess(e){
},
onVideoSaveSuccess(e){
console.error("拍摄的视频保存成功:",e);
},
onImageSaveSuccess(){
console.error("拍摄的照片保存成功",e);
},
// 计算预览页面的一些尺寸
calcPreviewSize(){
this.previewWidth = this.screenWidth;
this.previewHeight = this.screenHeight;
let platform = uni.getSystemInfoSync().platform;
console.error("平台:"+platform+"宽度:",this.previewWidth," 高度:",this.previewHeight);
if(this.previewRatio === 1){
this.previewSizeStyle = 'design_size1_1';
}else if(this.previewRatio === 2){
this.previewSizeStyle = 'design_size4_3';
}else if(this.previewRatio === 3){
this.previewSizeStyle = 'design_size16_9';
}
this.previewHeight = this.previewWidth * 1.333333 * 2;// + ("android" === platform ? 40 : 0);
this.previewWidth = this.previewWidth * 2;// + ("android" === platform ? 40 : 0);
this.screenHeight = this.screenHeight * 2;
this.screenWidth = this.screenWidth * 2;
this.takePhotoBtnMarginBottom = ((this.screenHeight - this.previewHeight) / 2 + 50);
this.takePhotoBtnMarginBottom = this.takePhotoBtnMarginBottom < 200 ? 200 : this.takePhotoBtnMarginBottom;
// this.previewHeight = 500;
// let ratio;
// if(this.previewRatio === 1){
// ratio = 1;
// }else if(this.previewRatio === 2){
// ratio = 3.0 / 4.0;
// }else if(this.previewRatio === 3){
// ratio = 9.0 / 16.0;
// }
// this.previewHeight = this.previewWidth * ratio;
},
gotoResetLocation(){
uni.navigateTo({
url:'/pages/module/camera/reset-location/reset-location?latitude='+this.latitude+'&longitude='+this.longitude
})
},
takePhotoSuccess(e){
uni.showToast({
title:'~ 拍照成功 ~',
icon:'none'
})
},
doBackPage(){
uni.navigateBack({
delta:1
})
},
// 接受用户选择的新poi点
receivePoi(res){
this.address = res;
console.error("接收到:",res);
},
// 接收修改后的水印设置信息
receiveWaterInfo(res){
console.error("接收到了水印配置信息:",res);
this.showRemark = res.showRemark;
this.showAddress = res.showAddress;
this.remark = res.remark;
},
gotoWaterSetting(){
uni.navigateTo({
url:"/pages/module/camera/water-setting/water-setting?timeStr="+this.timeStr+"&dateStr="+this.dateStr+"&weekDay="+this.weekDay+"&address="+this.address
})
},
getWeekDay(){
this.weekDay = "星期"+"日一二三四五六".charAt(new Date().getDay());
},
startTimeCount(){
const $that = this;
$that.dateTimeInterval = setInterval(()=>{
$that.currentDate = new Date().getTime();
$that.dateStr = $that.getNowDate($that.currentDate);
$that.timeStr = $that.getNowTime($that.currentDate);
// console.error("时间L:",$that.timeStr,' ',$that.dateStr);
},3000);
},
// 切换摄像头
switchCamera(){
if(this.currentCamera === "0"){
this.currentCamera = "1";
this.$refs.cameraObj.openFront();
}else{
this.currentCamera = "0";
this.$refs.cameraObj.openBack();
}
},
// 延迟拍摄
delayTakePhoto(delay){
const $that = this;
$that.delayTakePhotoTime = delay;
$that.delayTakePhotoInterval = setInterval(()=>{
$that.delayTakePhotoTime -= 1;
// 清除取消计时器
if($that.delayTakePhotoTime <= 0){
if($that.delayTakePhotoInterval)
clearInterval($that.delayTakePhotoInterval);
$that.takePhoto();
}
},1000);
},
// 切换闪光灯
switchFlash(){
if(this.flashStatus === 0){
this.flashStatus = 1;
this.$refs.cameraObj.openFlash();
}else{
this.flashStatus = 0;
this.$refs.cameraObj.closeFlash();
}
},
// 获取插件回传的最优宽高比
receiveRatio(e){
console.error("接收到了最优的宽高比例:",e);
this.cameraRatio = e.detail.ratio;
},
// 切换比例模式
switchPriviewRatio(){
if(this.previewRatio === 3){
this.previewRatio = 2;
}else if(this.previewRatio == 2){
this.previewRatio = 3;
}else if(this.previewRatio == 1){
this.previewRatio = 2;
}
this.calcPreviewSize();
},
getLocation(){
const $that = this;
$that.address = '正在定位中~';
uni.getLocation({
type: 'gcj02',
geocode: true,
isHighAccuracy:true,
success:(res) => {
$that.latitude = res.latitude;
$that.longitude = res.longitude;
let data = res.address;
$that.address = data.city + data.district + " · "+ (data.poiName ? data.poiName : (data.street ? data.street:"")+(data.streetNum ? data.streetNum:""));
console.log('当前位置:' , $that.address);
// "country": "中国",
// "province": "上海市",
// "city": "上海市",
// "district": "嘉定区",
// "street": "宝乐路",
// "streetNum": "58号",
// "poiName": "阳光葡提公馆",
// "cityCode": "021"
// $that.$refs.cameraObj.addWaterText($that.address,$that.tempDateStr,$that.tempTimeStr,$that.weekDay);
}
});
},
takePhoto(){
console.error("开始拍照1")
if(!this.address){
uni.showToast({
title:'正在获取定位信息',
})
return;
}
this.tempTimeStr = this.timeStr;
this.tempDateStr = this.dateStr;
// this.$refs.cameraObj.addWaterText((this.showAddress ? this.address:''),this.tempDateStr,this.tempTimeStr,this.weekDay,(this.showRemark ? this.remark:''),"· 工友会 ·|水印相机");
// 设置水印
this.$refs.cameraObj.addWaterText({
"date":this.tempDateStr || "",
"logo":"·工友会·|水印相机",
"address":(this.showAddress ? this.address:""),
"time":this.tempTimeStr || "",
"week":this.weekDay || "",
"remark":(this.showRemark ? this.remark:"")
});
this.$refs.cameraObj.takePhoto();
},
getNowDate(dateTime) {
let date = new Date(dateTime);
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (month.toString().length == 1) {
month = "0" + month;
}
if (day.toString().length == 1) {
day = "0" + day;
}
return year + "-" + month + "-" + day;
},
getNowTime(dateTime) {
let date = new Date(dateTime);
let hours = date.getHours();
let min = date.getMinutes();
// let sec = date.getSeconds();
if (hours.toString().length == 1) {
hours = "0" + hours;
}
if (min.toString().length == 1) {
min = "0" + min;
}
// if (sec.toString().length == 1) {
// sec = "0" + sec;
// }
return hours + ":" + min ;
},
}
}
</script>
<!-- <style src="@/pages/module/camera/camera.css"></style> -->
<!-- nvue必须要重新创建一个style标签来写新的css ,不能在上面引入外部css的style里写-->
<style>
.demo_flex_row{
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.marginRight20px {
margin-right: 40rpx;
}
.window{
background-color: white;
width: 750rpx;
position: absolute;
height: 1624rpx;
}
.camera_top_bar{
background-color: white;
height: 176rpx;
max-height: 176rpx;
padding-top: 88rpx;
padding-bottom: 16rpx;
flex-direction: row;
align-items: flex-end;
justify-content: space-between;
}
.design_size4_3{
width: 750rpx;
height: 1000rpx;
}
.design_size16_9{
width: 750rpx;
height: 1333rpx;
}
.design_size1_1{
width: 750rpx;
height: 750rpx;
}
.icon_size{
width: 48rpx;
height: 48rpx;
}
.icon_size2{
width: 42rpx;
height: 42rpx;
}
.ratio_view{
border: 2rpx solid #979797;
border-radius: 6px;
padding: 2rpx 12rpx;
color: #333333;
width: 60px;
margin-right: 65rpx;
text-align: center;
}
.delay_time_text_size{
color: white;
font-size: 150rpx;
}
.delay_time_layout{
position: absolute;
top: 0px;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 100;
font-weight: bold;
flex-direction: row;
justify-content: center;
align-items: center;
}
.camera_layout{
position: absolute;
top: 176rpx;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 100;
}
.camera_view{
position: absolute;
top: 0rpx;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 100;
/* border: 5rpx solid #CE3D3A; */
}
.text_white {
color: white;
}
/* 新的水印布局css START */
.water_layout{
align-items: flex-start;
justify-content: flex-end;
z-index: 200;
}
/* 新的水印布局css END */
.water_text_layout{
position: relative;
top: 0rpx;
bottom: 0rpx;
left: 10px;
right: 0rpx;
z-index: 100;
}
.water_text_location{
position: absolute;
right: 20px;
top: 860rpx;
z-index: 100;
}
.water_text_location_icon{
width: 45rpx;
height: 45rpx;
}
.water_text_line{
height: 32px;
width: 5px;
background-color: #CE3D3A;
}
.water_text_bottom_20{
position: absolute;
bottom: 20rpx;
left: 0rpx;
}
.water_text_bottom_40{
position: absolute;
bottom: 40rpx;
left: 0rpx;
}
.root_layout{
position: absolute;
width: 750rpx;
top: 0rpx;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
z-index: 50;
/* position: relative; */
}
.take_photo_layout{
position: absolute;
bottom: 0rpx;
left: 0rpx;
right: 0rpx;
height: 448rpx;
}
.ovay_red{
width: 145rpx;
height: 145rpx;
background-color: #CE3D3A;
/* border: 8rpx solid white; */
border-radius: 100rpx;
}
.ovay_red_border{
border: 2rpx solid #F0F0F0;
background-color: #CE3D3A;
width: 130rpx;
height: 130rpx;
border-radius: 100rpx;
}
.ovay_red_border:active{
background-color: #CCC;
border: 2rpx solid red;
}
.px14{
font-size: 14px;
}
.px30{
font-size: 30px;
}
.px40{
font-size: 80rpx;
}
.marginLeft5px {
margin-left: 10rpx;
}
.marginLeft10px {
margin-left: 20rpx;
}
.marginLeft15px {
margin-left: 30rpx;
}
</style>