当前位置:   article > 正文

uniapp 水印/相机/授权位置、相机、相册权限_uni app安卓相机

uni app安卓相机

自定义相机水印

  1. <template>
  2. <view>
  3. <view v-if="loaded && cameraEnable">
  4. <camera :device-position="device" :flash="flash" @error="error" resolution="high"
  5. :style="{ width: '100%',position: 'relative', height: mainHeight + 'px' }">
  6. <cover-view class="waterMark-center">
  7. <cover-view class="waterMark">
  8. <!-- 时间 -->
  9. <cover-view class="dec">{{nowDate}}</cover-view>
  10. <!-- 地址 -->
  11. <cover-view class="dec">{{address}}</cover-view>
  12. </cover-view>
  13. </cover-view>
  14. <!-- 旋转摄像头 -->
  15. <cover-image @click="cameraRotate" class="rotate" src="/static/camera/rotate.png"></cover-image>
  16. <!-- 打开/关闭 闪关灯 -->
  17. <cover-image @click="switchLights" class="lights" :src="lightsImg"></cover-image>
  18. <!-- 拍照 -->
  19. <cover-view class="cameraBtn" @click="takePhoto">
  20. <cover-view class="cameraBtn-inner"></cover-view>
  21. </cover-view>
  22. <!-- 底部预览生成图片 -->
  23. <cover-view class="bottomBg" v-if="fileList.length > 0">
  24. <cover-view>
  25. <cover-view @click="ViewImage(index)" class="imgBox" v-for="(item,index) in fileList"
  26. :key="index">
  27. <cover-image class="imgItem" :src="item.url" mode="aspectFill"></cover-image>
  28. <cover-view class="cu-tag" @tap.stop="DelImg" :data-index="index">
  29. <cover-image class="iconClose" src="/static/camera/close.png"
  30. mode="aspectFill"></cover-image>
  31. </cover-view>
  32. </cover-view>
  33. </cover-view>
  34. </cover-view>
  35. </camera>
  36. <!-- canvas元素,利用它的功能,实现添加水印 -->
  37. <canvas :style="{ width: cwidth + 'px', height: cheight + 'px', position: 'absolute', top: '-999999999px'}" canvas-id="firstCanvas"></canvas>
  38. </view>
  39. <view v-else>
  40. 相机不可用
  41. </view>
  42. </view>
  43. </template>
  1. <script setup>
  2. import {
  3. ref,
  4. reactive,
  5. toRefs,
  6. getCurrentInstance,
  7. computed,
  8. onMounted
  9. } from 'vue'
  10. import {
  11. onLoad,
  12. onShow
  13. } from '@dcloudio/uni-app'
  14. import { getCurrentDate } from '@/common/date.js'
  15. // 引入SDK核心类
  16. // import QQMapWX from '@/common/qqmap-wx-jssdk1.2/qqmap-wx-jssdk.js'
  17. const props = defineProps({
  18. // camera 组件高度
  19. mainHeight: {
  20. type: Number,
  21. default: 380
  22. },
  23. isPageLoading: {
  24. type: Boolean,
  25. default: false
  26. }
  27. })
  28. const emit = defineEmits(['onBack', 'update:isPageLoading'])
  29. let { ctx } = getCurrentInstance()
  30. let loaded = ref(false)
  31. let cameraEnable = ref(false)
  32. // 防止mounted与onShow冲突
  33. let loop = ref(false)
  34. let fileList = ref([])
  35. let data = reactive({
  36. device: 'back', //前置或后置摄像头,值为front, back
  37. flash: 'off', // 闪光灯,值为auto, on, off
  38. nowDate: '',
  39. address: '', //当前地址信息
  40. cwidth: 50, // canvas 元素宽度
  41. cheight: 50 // canvas 元素高度
  42. })
  43. let {
  44. device,
  45. flash,
  46. nowDate,
  47. address,
  48. cwidth,
  49. cheight
  50. } = toRefs(data)
  51. let lightsImg = computed(() => {
  52. return data.flash === 'off' ? '/static/camera/lights_on.png' : '/static/camera/lights.png'
  53. })
  54. onLoad((option) => {
  55. if (option.list.length > 0) {
  56. fileList.value = JSON.parse(option.list)
  57. }
  58. // 获取当前日期时间
  59. data.nowDate = getCurrentDate()
  60. })
  61. onShow(() => {
  62. if (loaded.value && !loop.value) {
  63. // 轮询当前相机权限状态,当用户授权则将cameraEnable设置为true
  64. loopGetCameraInfo()
  65. }
  66. })
  67. onMounted(() => {
  68. setTimeout(() => {
  69. loaded.value = true
  70. loopGetCameraInfo()
  71. }, 1000);
  72. })
  73. function loopGetCameraInfo() {
  74. loop.value = true;
  75. getAuthInfo();
  76. setTimeout(() => {
  77. if (!loaded.value) {
  78. loopGetCameraInfo()
  79. } else {
  80. if (!cameraEnable.value) {
  81. loopGetCameraInfo()
  82. } else {
  83. loop.value = false
  84. }
  85. }
  86. }, 500);
  87. }
  88. // 判断相机、相册、位置是否授权------------授权建议写在外面
  89. function getAuthInfo() {
  90. uni.getSetting({
  91. success(res) {
  92. const authSetting = res.authSetting;
  93. if (authSetting['scope.camera'] && authSetting['scope.writePhotosAlbum'] && authSetting['scope.userLocation']) {
  94. // 已经授权
  95. emit('update:isPageLoading', true)
  96. cameraEnable.value = true;
  97. getLocation()
  98. } else {
  99. emit('update:isPageLoading', true)
  100. cameraEnable.value = false;
  101. }
  102. }
  103. });
  104. }
  105. function saveImg(path) {
  106. // 已经授权
  107. uni.saveImageToPhotosAlbum({
  108. filePath: path,
  109. complete(res) {
  110. // console.log('保存图片', res);
  111. }
  112. })
  113. }
  114. // 获取当前地址
  115. function getLocation() {
  116. // 获取当前位置信息
  117. uni.getLocation({
  118. type: 'gcj02',
  119. success: function(res) {
  120. data.address = 'test11111111111111111111111'
  121. // let qqmapsdk = new QQMapWX({
  122. // key: "自己申请的腾讯地图key"
  123. // })
  124. // // 根据经纬度反解析出地址名称
  125. // qqmapsdk.reverseGeocoder({
  126. // location: {
  127. // latitude: res.latitude,
  128. // longitude: res.longitude
  129. // },
  130. // success(addressRes) {
  131. // },
  132. // fail(err) {
  133. // // getLocation()
  134. // console.log(err, '获取地址失败');
  135. // }
  136. // })
  137. },
  138. fail(err) {
  139. console.log(err);
  140. uni.showToast({
  141. title: err.errMsg,
  142. icon: 'none'
  143. })
  144. }
  145. })
  146. }
  147. // 旋转摄像头
  148. function cameraRotate() {
  149. if (data.device == 'front') {
  150. data.device = 'back'
  151. } else {
  152. data.device = 'front'
  153. }
  154. }
  155. // 打开/关闭 闪光灯
  156. function switchLights() {
  157. data.flash = data.flash === 'off' ? 'on' : 'off'
  158. }
  159. // 删除水印照片
  160. function DelImg(e) {
  161. let index = e.currentTarget.dataset.index
  162. uni.showModal({
  163. content: '确定要删除这张照片吗?',
  164. cancelText: '取消',
  165. confirmText: '确认',
  166. success: res => {
  167. if (res.confirm) {
  168. fileList.value.splice(index, 1)
  169. }
  170. }
  171. })
  172. }
  173. // 查看照片
  174. function ViewImage(index) {
  175. let imgs = [];
  176. for (let i = 0; i < ileList.value.length; i++) {
  177. imgs.push(ileList.value[i].url);
  178. }
  179. uni.previewImage({
  180. urls: imgs,
  181. current: index
  182. })
  183. }
  184. // 点击拍照
  185. function takePhoto() {
  186. if (!data.address) {
  187. uni.showToast({
  188. title: '请重新获取当前位置',
  189. icon: 'none'
  190. })
  191. return
  192. }
  193. uni.showLoading({
  194. mask: true
  195. })
  196. // 创建并返回 camera 组件的上下文 cameraContext 对象
  197. const cameraContext = uni.createCameraContext();
  198. // 拍照
  199. cameraContext.takePhoto({
  200. quality: 'high', // 图片质量高
  201. success: (res) => {
  202. let tempImagePath = res.tempImagePath; // 临时图片路径
  203. uni.getImageInfo({
  204. src: tempImagePath,
  205. success(imgRes) {
  206. data.cwidth = imgRes.width / 3
  207. data.cheight = imgRes.height / 3
  208. drawWaterMark(imgRes.path)
  209. },
  210. fail() {
  211. uni.hideLoading()
  212. }
  213. })
  214. }
  215. });
  216. }
  217. // 画水印
  218. function drawWaterMark(path) {
  219. let markctx = uni.createCanvasContext('firstCanvas', ctx)
  220. markctx.drawImage(path, 0, 0, data.cwidth, data.cheight);
  221. markctx.setFontSize(14); // 设置字体大小为 10px
  222. markctx.setFillStyle('#FFFFFF'); // 设置颜色为白色
  223. let textToWidth = data.cwidth * 0.03; // 绘制文本的左上角x坐标位置
  224. let textToHeight1 = data.cheight * 0.10; // 绘制文本的左上角y坐标位置
  225. // let textToHeight2 = data.cheight * 0.16;
  226. // 绘制日期和时间
  227. markctx.fillText(data.nowDate, textToWidth, textToHeight1);
  228. let first = 0
  229. for (var i = 0; i < data.address.length; i++) {
  230. if(first > data.address.length) {
  231. break
  232. }
  233. let str = data.address.substring(first, first + 20)
  234. // 绘制地址
  235. let numSpace = ((i + 1) * 6 + 10) / 100
  236. markctx.fillText(str, textToWidth, data.cheight * numSpace);
  237. first += 20
  238. }
  239. // 绘制地址
  240. // markctx.fillText(data.address, textToWidth, textToHeight2);
  241. markctx.draw(false, () => {
  242. setTimeout(() => { // 保证第一张图片渲染正常 -- 定时300有时候也会不正常(多测试)--至少400
  243. uni.canvasToTempFilePath({
  244. canvasId: 'firstCanvas',
  245. success(res) {
  246. fileList.value.push({
  247. url: res.tempFilePath
  248. })
  249. emit('onBack', fileList.value)
  250. uni.hideLoading()
  251. saveImg(res.tempFilePath)
  252. },
  253. fail(err) {
  254. uni.hideLoading()
  255. console.log('合成失败', err);
  256. }
  257. }, ctx)
  258. }, 300)
  259. })
  260. }
  261. // 用户不允许使用摄像头时触发
  262. function error(e) {
  263. // uni.showToast({
  264. // title: e.detail.errMsg,
  265. // icon: 'none'
  266. // })
  267. }
  268. </script>
  1. <style lang="scss" scoped>
  2. .waterMark-center {
  3. display: flex;
  4. flex-direction: row;
  5. align-items: center;
  6. justify-content: center;
  7. height: 32%;
  8. width: 750rpx;
  9. }
  10. .waterMark {
  11. width: 750rpx;
  12. box-sizing: border-box;
  13. padding: 30rpx;
  14. color: #EEEEEE;
  15. font-size: 34rpx;
  16. .dec {
  17. width: 100%;
  18. white-space: pre-wrap;
  19. margin-bottom: 15rpx;
  20. }
  21. }
  22. .cameraBtn {
  23. width: 120rpx;
  24. height: 120rpx;
  25. line-height: 120rpx;
  26. border: 6rpx #FFFFFF solid;
  27. border-radius: 50%;
  28. padding: 8rpx;
  29. position: absolute;
  30. left: calc(50% - 60rpx);
  31. bottom: 210rpx;
  32. &-inner {
  33. width: 100%;
  34. height: 100%;
  35. border-radius: 50%;
  36. background-color: #FFFFFF;
  37. text-align: center;
  38. color: #007AFF;
  39. }
  40. }
  41. .rotate {
  42. width: 52rpx;
  43. height: auto;
  44. position: absolute;
  45. right: 44rpx;
  46. bottom: 580rpx;
  47. }
  48. .lights {
  49. width: 40rpx;
  50. height: auto;
  51. position: absolute;
  52. right: 50rpx;
  53. bottom: 450rpx;
  54. }
  55. .bottomBtn {
  56. width: 100%;
  57. height: 150rpx;
  58. padding-bottom: 15rpx;
  59. position: absolute;
  60. bottom: 0;
  61. left: 0;
  62. text-align: center;
  63. display: flex;
  64. justify-content: space-between;
  65. .btn {
  66. width: 30%;
  67. height: 150rpx;
  68. font-size: 34rpx;
  69. color: #FFFFFF;
  70. line-height: 150rpx;
  71. }
  72. }
  73. .bottomBg {
  74. width: 100%;
  75. height: 170rpx;
  76. box-sizing: border-box;
  77. padding: 20rpx 30rpx 40rpx;
  78. position: absolute;
  79. bottom: 0;
  80. left: 0;
  81. background-color: rgba(0, 0, 0, .8);
  82. display: flex;
  83. justify-content: space-between;
  84. align-items: center;
  85. .imgBox {
  86. width: 110rpx;
  87. height: 110rpx;
  88. float: left;
  89. margin-right: 40rpx;
  90. position: relative;
  91. .cu-tag {
  92. position: absolute;
  93. right: 0;
  94. top: 0;
  95. border-bottom-left-radius: 2px;
  96. padding: 3px 5px;
  97. height: auto;
  98. background-color: rgba(0, 0, 0, 0.5);
  99. font-size: 10px;
  100. vertical-align: middle;
  101. font-family: Helvetica Neue, Helvetica, sans-serif;
  102. white-space: nowrap;
  103. color: #ffffff;
  104. }
  105. }
  106. .imgItem {
  107. width: 110rpx;
  108. height: 110rpx;
  109. }
  110. }
  111. .iconClose {
  112. width: 20rpx;
  113. height: 20rpx;
  114. }
  115. </style>

授权

    // 手动授权【摄像头】
    function getAuth() {
        // 获取摄像头权限
        uni.getSetting({
            success(res) {
                console.log("auth res", res);
                const authSetting = res.authSetting;
                if (authSetting['scope.camera'] ) {
                    // 已经授权
                    cameraEnable.value = true;
                } else {
                    // 未授权
                   
                    uni.authorize({
                        scope: 'scope.camera',
                        success(resSuccess) {
                            getAuthInfo()
                        },
                        fail(resFail) {
                            guideAuth()
                        }
                    });
                }
            }
        });
    }
    
    function guideAuth(chinastr){
        // 引导用户授权
        uni.showModal({
            title: '授权',
            content: '需要您授权获取摄像头权限',
            success: function(res) {
                if (res.confirm) {
                    uni.openSetting({
                        success(resOpenSetting) {
                            const authSetting = resOpenSetting.authSetting
                            if (authSetting && authSetting['scope.camera'] ) {
                                getAuthInfo()
                            } else {
                                uni.showToast({
                                    icon: 'none',
                                    title: '请授权所需权限',
                                    duration: 1500
                                });
                            }
                        }
                    });
                } else if (res.cancel) {
                    uni.showToast({
                        icon: 'none',
                        title: '您拒绝授权小程序获取摄像头权限',
                        duration: 1500
                    });
                }
            }
        });
    }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/274456
推荐阅读
相关标签
  

闽ICP备14008679号