更新记录

2.2.6(2022-09-22)

修复水印bug

2.2.5(2022-09-18)

增加自定义图片水印功能

查看更多

平台兼容性

Android Android CPU类型 iOS
适用版本区间:5.0 - 11.0 armeabi-v7a:未测试,arm64-v8a:未测试,x86:未测试 适用版本区间:9 - 15

原生插件通用使用流程:

  1. 购买插件,选择该插件绑定的项目。
  2. 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
  3. 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
  4. 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
  5. 开发完毕后正式云打包

付费原生插件目前不支持离线打包。
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

温馨提示:可下载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的底边距
特别注意:插件默认不会将图片、视频存入媒体库相册,如果需要在拍照录像后保存到相册请设置 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>

上海栾青网络科技有限公司

15921627041 (同微信)

隐私、权限声明

1. 本插件需要申请的系统权限列表:

"android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问