uniapp做的项目,某些页面有拍照功能,就单纯的调用摄像头拍照,却无法对照片进行编辑标注。属于优化项,但是可以有的那种。
只是简单的涂鸦,像在图片上签名一样,没有那种美颜啥的功能,所以难度不是很大。思路也比较简单:
1.接收到相机拍摄到的图片
2.将图片导入进canvas中
3.对canvas监听开始触摸事件和触摸移动事件
4.将canvas导出图片,返回给上一个页面。
实现过程中参考了其他博主的文章,文章链接如下:
https://www.cnblogs.com/buaa17373407hjh/p/12970816.html
https://www.cnblogs.com/CaraganaMicrophylla/p/16381145.html
两个方面,一个是拍照之后直接将图片传到编辑页面。第二个是,从图片预览去将图片传入编辑页面。
- uni.chooseImage({
- count: 1,
- sourceType: 拍照的话使用['camera'],
- sizeType: ['compressed'],
- success : function(res){
- uni.navigateTo({
- url:照片编辑页面的url,
- events: {
- acceptDataFromOpenedPage: function(data) {
- console.log(data)
- },
- getEditCompleteImg: function(imgData) {
- // 代码处理逻辑,用数组存id和资源
- picturesArray.push({
- id: 自定义值,
- src: imgData中的图片url
- })
- }
- },
- success:function(openRes){
- openRes.eventChannel.emit('acceptDataFromOpenerPage', { data: res.tempFilePaths[0] })
- }
- })
- },
- fail: function(error){
- console.log(error);
- },
- complete: function(res){
- console.log(res);
- }
- })
chooseImage方法和navigateTo方法在uniapp的官网都有具体文档。
https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage
uni.navigateTo(OBJECT) | uni-app官网
success是打开另一个页面成功后,将数据传过去,代码里面传递的是图片的url。
events是注册的事件监听,可以在图片编辑页面,重新将数据传递回来。
主要是调用uniapp的图片预览功能,支持长按弹出菜单项。代码如下
- uni.previewImage({
- urls, // 图片资源url组成的数组
- current, // 默认打开的下标
- longPressActions: {
- itemList:['编辑图片'],
- success:function(data){
- console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片')
- // 拿到图片的url urls[data.index]
- // 关闭图片预览,跳转到图片编辑页面
- plus.nativeUI.closePreviewImage();
- uni.navigateTo({
- url:图片编辑页面的url,
- events: {
- acceptDataFromOpenedPage: function(data) {
- console.log(data)
- },
- getEditCompleteImg: function(imgData) {
- console.log(imgData)
- // 和之前一样的处理逻辑
- }
- },
- success:function(res){
- res.eventChannel.emit('acceptDataFromOpenerPage', { data: urls[data.index] })
- }
- })
- },
- error:function(err){
- console.log(err)
- }
- }
- })
uni.chooseImage(OBJECT) | uni-app官网
需要一个canvas来将图片绘制。一个编辑保存按钮,一个清除重置按钮。
- uni.canvasToTempFilePath({
- canvasId: 'shareCanvas', // canvas元素的id值
- destHeight: this.initImgHeight, // initImgHeight是传入图片时获取到的图片高度
- destWidth: this.initImgWidth, // 传入图片原先的宽度
- success: function (res) {
- // eventChannel.emit('someEvent', {data: 'data from test page for someEvent'});
- vm.eventChannel.emit('getEditCompleteImg', {data: res.tempFilePath});
- // 返回页面
- uni.navigateBack()
- }
- })
- // 清除重新绘制
- let vm = this;
- console.log('重新绘制')
- // 重新绘制图片 targetImgUrl为原先图片的url editWidth是canvas的宽度
- vm.drawContext.drawImage(vm.targetImgUrl,0,0,vm.editWidth,vm.editHeight)
- vm.drawContext.draw()
- // 重新设置颜色 这是封装的一个方法,画笔颜色宽度什么的
- vm.updateDrawContext()
在mounted中拿到canvas的宽度,高度在拿到图片的高度宽度信息获取宽高比后,动态设置高度。
- uni.createSelectorQuery().in(this).select(canvas元素设置的类名).boundingClientRect(data => {
- // console.log(JSON.stringify(data))
- // {"id":"","dataset":{},"left":12,"right":308,"top":12,"bottom":315,"width":296,"height":303}
- // this.editHeight = data.height
-
- this.editWidth = data.width
- console.log('读取到的',this.editWidth)
- }).exec()
在onLoad里面获取图片的url,然后获取图片的高度和宽度存到data中。
- const ctx = uni.createCanvasContext(canvas元素设置的id值)
- // 设置线条
- this.drawContext = ctx
- let vm = this
- vm.eventChannel.on('acceptDataFromOpenerPage', function(data) {
- console.log(data)
- vm.targetImgUrl = data.data
- // 获取图片的宽高
- uni.getImageInfo({
- src: data.data,
- success: function (image) {
- vm.initImgWidth = image.width;
- vm.initImgHeight = image.height;
- console.log('图片高度:',vm.initImgHeight)
- console.log('图片宽度:',vm.initImgWidth)
- console.log('图片纵横比',image.width/image.height)
- // 避免图片拉伸,保持纵横比
- const widthHeight = image.height/image.width
- vm.editHeight = widthHeight*vm.editWidth
- console.log('画布的高度',vm.editHeight)
- console.log('画布的宽度',vm.editWidth)
- vm.drawContext.drawImage(data.data,0,0,vm.editWidth,vm.editHeight)
- vm.drawContext.draw()
- // 设置画笔颜色
- vm.updateDrawContext()
- },
- error: function (err) {
- console.log(err)
- },
- complete:function(end){
- console.log(end)
- }
- });
- })
在onBackPress中设置
在getImageInfo中,已经将图片绘制到canvas中。剩下的就是设置canvas的开始触摸事件,触摸滑动事件,触摸结束事件等。
具体逻辑可以看这篇文章,canvas签名的逻辑,也是参考文章中的链接:
uniapp中使用canvas - 小兔儿_乖乖 - 博客园
- touchstart: function (e) {
- // 取出x、y的值
- let {
- x,
- y
- } = e.changedTouches[0]
- // 绘制线条起点
- this.drawContext.beginPath()
- this.drawContext.moveTo(x, y)
- // 起点与移动的连接断开
- this.moveX = ''
- this.moveY = ''
- },
- touchmove: function (e) {
- // 取出x, y的值
- let {
- x,
- y
- } = e.changedTouches[0]
- // 防止线条出现断点
- if (this.moveX && this.moveY) {
- this.drawContext.moveTo(this.moveX, this.moveY)
- this.drawContext.lineTo(this.moveX, this.moveY)
- }
- this.drawContext.lineTo(x, y)
- this.moveX = x
- this.moveY = y
- this.drawContext.stroke()
- // ture,保留之前的内容
- this.drawContext.draw(true)
- },