uniapp+uView 实现拍照水印定位信息

1、先上效果图:

                 

代码目录结构截图:

 2、照片列表页代码

<template>
	<view class="u-upload">
		<view class="u-list-item u-preview-wrap" v-for="(item, index) in imgList" :key="index"
		:style="{
			width: 200,
			height: 200
		}">
		
			<view class="u-delete-icon" @click="deleteItem(index)" :style="{
					background: '#fa3534'
				}">
				<u-icon class="u-icon" name="close" size="20" color="#ffffff"></u-icon>
			</view>
			<image @click="lookImg(index)" class="u-preview-image"
							:src="item.path"></image>
			
		</view>
		<view style="display: inline-block;" @click="gotoCamera" v-if="imgList.length<8">
			<slot name="addBtn"></slot>
			<view class="u-list-item u-add-wrap" hover-class="u-add-wrap__hover" hover-stay-time="150"
				:style="{
					width: 200,
					height: 200
				}">
				<u-icon name="camera" size="80"></u-icon>
			</view>
		</view>
	</view>	
</template>

<script>
	export default {
		data() {
			return {
				imgList:[],
			}
		},
		methods: {
			// 跳转到拍照页面
			gotoCamera(){
				uni.$u.route('/pages/camera/camera');
			},
			// 删除图片
			deleteItem(index){
				let that = this;
				uni.showModal({
					title: '提示',
					content: '您确定要删除此张照片吗?',
					success: async (res) => {
						if (res.confirm) {
							that.imgList.splice(index,1)
						}
					}
				});
			},
			lookImg(index){
				let photoList = this.imgList.map(item => {
					return item.path;
				});
				// 预览图片
				uni.previewImage({
					current: index,
					urls: photoList,
				});
			},
		}
	}
</script>

<style scoped lang="scss">
	.u-upload {
		// @include vue-flex;
		display: flex;
		flex-wrap: wrap;
		align-items: center;
	}
	.u-add-tips {
		margin-top: 20rpx;
		line-height: 40rpx;
	}
	.u-delete-icon {
		position: absolute;
		top: 10rpx;
		right: 10rpx;
		z-index: 10;
		background-color: red;
		border-radius: 100rpx;
		width: 44rpx;
		height: 44rpx;
		// @include vue-flex;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	 
	.u-icon {
		// @include vue-flex;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	.u-list-item {
		width: 200rpx;
		height: 200rpx;
		overflow: hidden;
		margin: 10rpx;
		background: rgb(244, 245, 246);
		position: relative;
		border-radius: 10rpx;
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		align-items: center;
		justify-content: center;
	}
		 
	.u-preview-wrap {
		border: 1px solid rgb(235, 236, 238);
	}
	.u-preview-image {
		display: block;
		width: 100%;
		height: 100%;
		border-radius: 10rpx;
	}
</style>

3、拍照页面代码

        注意两点:

        1、代码中的 key: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"   换成自己的,这里的key是申请腾讯位置服务获取的秘钥,如何申请请参考这篇博客 :https://www.cnblogs.com/1549983239yifeng/p/14750266.html

        2、如果要获取定位信息,需要在Hbuilder中勾选位置接口,如下图

<template>
	<view>
		<camera :device-position="device" :flash="flash" @error="error" :style="{ width: '100%',position: 'relative', height: getHeight + 'px' }">
			<cover-view class="topBox">
				<cover-view class="topItem">{{nowWeek}}</cover-view>
				<cover-view class="topItem">{{nowTime +' '+nowTime2}}</cover-view>
				<cover-view class="topItem">{{address}}</cover-view>
			</cover-view>
			
			<cover-image @click="xzBtn" class="xzImg" src="https://cdn.zhoukaiwen.com/xz.png"></cover-image>
			<cover-image @click="positionBtn" class="positionImg" src="/static/images/dingwei.png"></cover-image>
			
			<cover-view class="cameraBtn" @click="takePhoto">
				<cover-view class="cameraBtn2"></cover-view>
			</cover-view>
			
		</camera>
		<view style="position: absolute;top: -999999px;">
			<view><canvas :style="{ width: w, height: h }" canvas-id="firstCanvas"></canvas></view>
		</view>
	</view>
</template>

<script>
	import QQMapWX from "@/common/qqmap-wx-jssdk.js";
	export default {
		data() {
			return {
				getHeight: '200',
				device: 'back', //前置或后置摄像头,值为front, back
				flash: 'off', //闪光灯,值为auto, on, off
				nowTime: '', //日期
				nowTime2: '', //时间
				nowTime2: '', //时间
				nowWeek: '', // 周几
				address: '',	//当前地址信息
				city: '',
				district: '',
				name:'',
				imgList: [
					
				],
				imgListData: '',

				rreportShow: false, //选择照片备注内容弹窗
				
				src:'',
				w:'',
				h:''
			}
		},
		onLoad() {
			const that = this;
			uni.getSystemInfo({
				success: function(res) {
					that.getHeight = res.windowHeight;
				}
			});
			this.getTime();
			uni.getLocation({
				type: 'wgs84',
				success: function(res) {

					let qqmapsdk = new QQMapWX({
						key: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx" //自己申请的key
					});
					qqmapsdk.reverseGeocoder({
						location: {
							latitude: res.latitude,
							longitude: res.longitude
						},
						success(addressRes) {
							that.address = addressRes.result.address;
							that.city = addressRes.result.address_component.city;
							that.district = addressRes.result.address_component.district;
						},
						fail(res) {}
					});
				}
			});
		},
		methods: {
			xzBtn() {
				if (this.device == 'front') {
					this.device = 'back'
				} else {
					this.device = 'front'
				}
			},
			// 点击拍照
			takePhoto() {
				var that = this;
				if (this.imgList.length < 3) {
					const ctx = uni.createCameraContext();
					ctx.takePhoto({
						quality: 'high',
						success: (ress) => {
							var tempImagePath = ress.tempImagePath;
							// 获取图片信息
							uni.getImageInfo({
								src: ress.tempImagePath,
								success: res => {
									that.w = res.width / 3 + 'px';
									that.h = res.height / 3.01 + 'px';
									let ctx = uni.createCanvasContext('firstCanvas'); /** 创建画布 */
									//将图片src放到cancas内,宽高为图片大小
									
									ctx.drawImage(ress.tempImagePath, 0, 0, res.width / 3, res.height / 3);
									
									ctx.setFontSize(18);
									ctx.setFillStyle('#FFFFFF');
									ctx.setTextAlign('center');
							// 		// ctx.rotate(30 * Math.PI / 180);//0.03
									let textToWidth = (res.width / 3) * 0.5;
									let textToHeight = (res.height / 3) * 0.9;
									ctx.fillText(that.nowTime2, textToWidth, textToHeight);
							
									ctx.setFontSize(12);
									let textToHeight2 = (res.height / 3) * 0.94;
									ctx.fillText(that.nowTime + ' ' + that.nowWeek, textToWidth, textToHeight2);
									ctx.setFontSize(9);
									let textToHeight3 = (res.height / 3) * 0.98;
									ctx.fillText(' 📍 '+ that.address, textToWidth, textToHeight3);
									
							
									ctx.draw(false, () => {
										setTimeout(() => {
											uni.canvasToTempFilePath({
												canvasId: 'firstCanvas',
												success: res1 => {
													tempImagePath = res1.tempFilePath;
													// console.log('----------',tempImagePath);
												
													
													uni.getFileSystemManager().readFile({// 【重点来啦】人家自提供的转码API
														filePath:tempImagePath,// 所需转码图像路径
														encoding:"base64",// 转码类型
														success:(res)=>{
															
														    // 生成base64
														    let imageBase64 = 'data:image/png;base64,'+res.data;
															let pages = getCurrentPages();
															//prevPage 是获取上一个页面的js里面的pages的所有信息。 -2 是上一个页面,-3是上上个页面以此类推。
															let prevPage = pages[pages.length - 2];
															// 将数据返回上一个页面
															prevPage.$vm.imgList.push({
																path: tempImagePath,
																date: that.nowTime,
																time: that.nowTime3,
																week: that.nowWeek,
																address: that.address,
																imageBase64: imageBase64
															})
															uni.navigateBack();
														}
													})
													
													
													// console.log(this.imgList);
													
													// var arr = this.imgList
													// var str = '';
													// for (var i = 0; i < arr.length; i++) {
													// 	str += arr[i].src + ",";
													// }
													// this.imgListData = str;
													// console.log(this.imgListData)
												}
											});
										}, 1000);
									});
								}
							});
						}
					});
				} else {
					uni.showToast({
						title: '最大上传3张照片',
						duration: 2000,
						icon: 'none'
					});
				}

			},
			// 定位选择
			positionBtn(){
				let that = this
				uni.chooseLocation({
					success: (res) => {
						that.address = that.city+that.district+res.name
					}
				})
			},
			getTime: function() {
				var weekarr = new Array("日", "一", "二", "三", "四", "五", "六");
				var date = new Date(),
					year = date.getFullYear(),
					month = date.getMonth() + 1,
					day = date.getDate(),
					hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(),
					minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(),
					second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
				month >= 1 && month <= 9 ? (month = "0" + month) : "";
				day >= 0 && day <= 9 ? (day = "0" + day) : "";
				var timer = year + '-' + month + '-' + day;
				var timer3 = hour + ':' + minute + ':' + second;
				var timer2 = hour + ':' + minute
				this.nowTime = timer;
				this.nowTime2 = timer2;
				this.nowTime3 = timer3;
				this.nowWeek = '星期' + weekarr[date.getDay()];

				// console.log(this.nowTime);
				// console.log(this.nowTime2);
			},
			error(e) {
				console.log(e.detail);
			},
			goBack(){
				uni.navigateBack({
						delta:1,//返回层数,2则上上页
				})
			}
		}
	}		
</script>

<style lang="scss">
	.topBox {
		width: 750rpx;
		box-sizing: border-box;
		padding-top: 200rpx;
		padding-left: 30rpx;
		color: #EEEEEE;
		font-size: 34rpx;

		.topItem {
			width: 100%;
			white-space: pre-wrap;
			margin-bottom: 15rpx;
		}
	}
	.xzImg {
		width: 52rpx;
		height: auto;
		position: absolute;
		right: 44rpx;
		bottom: 580rpx;
	}
	.positionImg {
		width: 55rpx;
		height: auto;
		position: absolute;
		right: 44rpx;
		bottom: 450rpx;
	}
	.cameraBtn {
		width: 120rpx;
		height: 120rpx;
		line-height: 120rpx;
		border: 6rpx #FFFFFF solid;
		border-radius: 50%;
		padding: 8rpx;
		position: absolute;
		left: calc(50% - 60rpx);
		bottom: 210rpx;
	}
	.cameraBtn2 {
		width: 100%;
		height: 100%;
		border-radius: 50%;
		background-color: #FFFFFF;
		text-align: center;
		color: #007AFF;
	}
</style>

<think> 首先,用户的问题是基于提供的参考资料,他想查找UniAppApp实现相机拍照与裁剪功能的方法。我需要参考给定的三个引用内容来回答。 引用内容总结: - 引用[1]: 描述了使用uniapp自定义插件来实现相机功能,包括自定义界面、拍照、录制等。通过一个自定义组件 `<camera-view>` 来实现- 引用[2]: 讨论了uniapp实现多端图片上传、拍照上传,包括水印功能、自适应布局(使用rpx)、代码复用等。提到了使用 `uni.chooseImage` 和 `sourceType: 'camera'` 来拍照上传。 - 引用[3]: 提到了一个具体的组件 "Ba-CameraView",用于uniapp的自定义相机插件,支持缩放和裁剪。 用户的需求是:在UniAppApp实现相机拍照与裁剪功能。所以,我需要从这些引用中提取相关信息,并提供实现方法。 关键点: - UniApp原生提供了 `uni.chooseImage` API 来访问相机或相册,但这可能无法自定义UI。 - 对于高度自定义的相机界面(如添加水印、裁剪等),需要开发自定义原生插件或使用现有组件。 - 引用中提到了一些自定义组件:`<camera-view>` 和 `<Ba-CameraView>`。 回答结构: 1. **介绍标准方法**:使用 UniApp 内置的 `uni.chooseImage` API 拍照,但这可能不支持裁剪。 2. **推荐自定义方法**:参考引用,使用自定义原生插件或组件来实现高度自定义的相机功能。 3. **实现步骤**: - 使用 `uni.chooseImage` 的基本方法。 - 如果需要自定义UI,开发或使用自定义组件(如 `<camera-view>` 或 `<Ba-CameraView>`)。 - 具体到裁剪功能:可以在拍照后使用 `uni.canvas` 或第三方库进行裁剪。 4. **提供示例代码**:基于引用中的片段,给出简单的代码示例。 5. **回答问题**:确保覆盖拍照和裁剪两个部分。 6. **生成相关问题**:根据系统指令,在回答末尾添加相关问题。 最后,回答必须使用中文,符合系统级指令:行内数学表达式用 `$...$`(但在这个上下文中不太可能用到数学,所以可能不需要),独立公式用 `$$...$$`(同样,可能不适用),确保LaTeX语法正确,添加引用标识。 引用标识示例:在相关段落末尾添加 `[^1]` 等。 回答结构: - 引言:简要解释方法。 - 具体方法分点。 - 代码示例。 - 生成相关问题。 </think> ### UniAppApp实现相机拍照与裁剪功能的方法 在UniApp中,App实现相机拍照与裁剪功能通常有两种方式:一是使用UniApp内置API(如`uni.chooseImage`),它支持基础拍照但自定义能力有限;二是通过自定义原生插件或组件来实现高度定制的相机界面和裁剪功能。下面我将基于您的参考资料,逐步解释实现方法。 #### 1. **基础方法:使用UniApp内置API拍照** UniApp提供了`uni.chooseImage` API,可用于调用系统相机拍照并获取图片文件: - **拍照实现**:设置`sourceType: 'camera'`来启动相机- **裁剪功能**:UniApp内置API不支持直接裁剪,但可在拍照后手动处理(例如使用`uni.canvas`绘制裁剪区域)。 - **示例代码**: ```javascript // 在UniApp页面的methods中 takePhoto() { uni.chooseImage({ sourceType: ['camera'], // 指定从相机拍照 count: 1, // 只拍一张 success: (res) => { const tempFilePath = res.tempFilePaths[0]; // 获取临时文件路径 console.log('拍照成功:', tempFilePath); // 后续可在这里添加裁剪逻辑,使用uni.canvas或第三方库 }, fail: (err) => { console.error('拍照失败:', err); } }); } ``` - **优点**:简单快捷,无需插件,适用于基础需求。 - **局限性**:无法自定义相机界面(如添加水印、调整布局),裁剪需额外代码实现,这在复杂场景(如精确裁剪位置)下可能性能不足[^2]。 #### 2. **高级方法:使用自定义原生插件或组件** 对于需要定制相机界面和集成裁剪的功能(如添加水印、拖拽位置),推荐参考引用中提到的自定义插件或组件: - **为什么需要自定义?** UniApp的系统相机调用限制自定义UI,而原生插件(如引用[1]的`<camera-view>`或引用[3]的`<Ba-CameraView>`)可直接嵌入原生代码,实现高度控制的相机功能包括裁剪[^1][^3]。 - **实现步骤**: 1. **引入自定义组件**:在UniApp中使用现有插件(如`Ba-CameraView`),或自行开发原生插件(Android/iOS原生代码封装)。 - 示例使用`Ba-CameraView`组件(引用[3]): ```html <!--UniApp页面的template中 --> <template> <view> <Ba-CameraView ref="cameraView" :load="loadData" @takePhotoSuccess="handlePhotoSuccess" @error="handleError" ></Ba-CameraView> <button @tap="takePhoto">拍照</button> </view> </template> <script> export default { methods: { takePhoto() { this.$refs.cameraView.takePhoto(); // 调用组件拍照方法 }, handlePhotoSuccess(tempFilePath) { console.log('拍照成功,临时路径:', tempFilePath); // 调用裁剪方法(例如使用uni.canvas或组件内置裁剪) this.cropImage(tempFilePath); }, cropImage(filePath) { // 使用uni.canvas绘制裁剪区域(示例) uni.canvasToTempFilePath({ canvasId: 'cropCanvas', destWidth: 300, // 目标宽度 destHeight: 300, // 目标高度 success: (res) => { console.log('裁剪后文件:', res.tempFilePath); // 上传或保存图片 } }); } } } </script> ``` 2. **集成裁剪功能**:自定义组件通常内置裁剪能力(如`Ba-CameraView`支持缩放和裁剪)。引用[2]提到,可通过`Canvas`绘制实现水印和裁剪,并利用`uni.upx2px`处理响应式布局(避免屏幕适配问题)[^2]。 3. **开发原生插件(可选)**:如果现有组件不满足需求,参考引用[1]开发原生插件: - Android使用Camera2 API,iOS使用AVFoundation。 - 在插件中实现拍照回调(`@takePhotoSuccess`)和内置信裁剪。 - 导出为UniApp组件供项目调用。 - **优点**:高度自定义(如添加水印、拖拽位置),性能优化(直接原生渲染),支持实时裁剪[^1][^2]。 - **推荐组件**: - `camera-view`(引用[1]):支持拍照、录制和事件回调。 - `Ba-CameraView`(引用[3]):开源组件,内置缩放和裁剪功能,可直接在UniApp插件市场安装。 - **注意事项**:自定义组件需测试多端兼容性;使用`rpx`单位处理布局(如引用[2]的`uni.upx2px`)以确保不同屏幕尺寸正常显示[^2]。 #### 3. **裁剪功能的具体实现** - **拍照后裁剪**:无论使用内置API或自定义组件,拍照后都可调用: - `uni.canvas`:绘制图片并导出裁剪区域。 - 第三方库如`uview-ui`的裁剪组件。 - **内置裁剪的组件**:如`Ba-CameraView`可直接在拍照时指定裁剪比例。 ### 总结 - **简单需求**:优先用`uni.chooseImage`拍照,手动添加裁剪逻辑(代码少但功能有限)。 - **复杂需求**:集成自定义组件(如`Ba-CameraView`)或开发原生插件,实现一体化拍照-裁剪流程。参考引用中的组件,能节省开发时间并支持水印等高级功能[^1][^2][^3]。 如果您有具体场景(如是否需要水印),可以提供更多细节,我会进一步优化建议。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值