• uniapp实现拍照涂鸦


    为什么要实现这个功能?

    uniapp做的项目,某些页面有拍照功能,就单纯的调用摄像头拍照,却无法对照片进行编辑标注。属于优化项,但是可以有的那种。

    实现思路和逻辑 

    只是简单的涂鸦,像在图片上签名一样,没有那种美颜啥的功能,所以难度不是很大。思路也比较简单:

    1.接收到相机拍摄到的图片

    2.将图片导入进canvas中

    3.对canvas监听开始触摸事件和触摸移动事件

    4.将canvas导出图片,返回给上一个页面。

     参考文章

    实现过程中参考了其他博主的文章,文章链接如下:

     https://www.cnblogs.com/buaa17373407hjh/p/12970816.html

     https://www.cnblogs.com/CaraganaMicrophylla/p/16381145.html

    实现代码 

     两个方面,一个是拍照之后直接将图片传到编辑页面。第二个是,从图片预览去将图片传入编辑页面。

    拍照逻辑

    1. uni.chooseImage({
    2. count: 1,
    3. sourceType: 拍照的话使用['camera'],
    4. sizeType: ['compressed'],
    5. success : function(res){
    6. uni.navigateTo({
    7. url:照片编辑页面的url,
    8. events: {
    9. acceptDataFromOpenedPage: function(data) {
    10. console.log(data)
    11. },
    12. getEditCompleteImg: function(imgData) {
    13. // 代码处理逻辑,用数组存id和资源
    14. picturesArray.push({
    15. id: 自定义值,
    16. src: imgData中的图片url
    17. })
    18. }
    19. },
    20. success:function(openRes){
    21. openRes.eventChannel.emit('acceptDataFromOpenerPage', { data: res.tempFilePaths[0] })
    22. }
    23. })
    24. },
    25. fail: function(error){
    26. console.log(error);
    27. },
    28. complete: function(res){
    29. console.log(res);
    30. }
    31. })

     chooseImage方法和navigateTo方法在uniapp的官网都有具体文档。

    https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage 

     uni.navigateTo(OBJECT) | uni-app官网

     success是打开另一个页面成功后,将数据传过去,代码里面传递的是图片的url。

    events是注册的事件监听,可以在图片编辑页面,重新将数据传递回来。

    选择照片逻辑

    主要是调用uniapp的图片预览功能,支持长按弹出菜单项。代码如下

    1. uni.previewImage({
    2. urls, // 图片资源url组成的数组
    3. current, // 默认打开的下标
    4. longPressActions: {
    5. itemList:['编辑图片'],
    6. success:function(data){
    7. console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片')
    8. // 拿到图片的url urls[data.index]
    9. // 关闭图片预览,跳转到图片编辑页面
    10. plus.nativeUI.closePreviewImage();
    11. uni.navigateTo({
    12. url:图片编辑页面的url,
    13. events: {
    14. acceptDataFromOpenedPage: function(data) {
    15. console.log(data)
    16. },
    17. getEditCompleteImg: function(imgData) {
    18. console.log(imgData)
    19. // 和之前一样的处理逻辑
    20. }
    21. },
    22. success:function(res){
    23. res.eventChannel.emit('acceptDataFromOpenerPage', { data: urls[data.index] })
    24. }
    25. })
    26. },
    27. error:function(err){
    28. console.log(err)
    29. }
    30. }
    31. })

     uni.chooseImage(OBJECT) | uni-app官网

    图片编辑逻辑 

    需要一个canvas来将图片绘制。一个编辑保存按钮,一个清除重置按钮。

    编辑保存按钮逻辑 

    1. uni.canvasToTempFilePath({
    2. canvasId: 'shareCanvas', // canvas元素的id值
    3. destHeight: this.initImgHeight, // initImgHeight是传入图片时获取到的图片高度
    4. destWidth: this.initImgWidth, // 传入图片原先的宽度
    5. success: function (res) {
    6. // eventChannel.emit('someEvent', {data: 'data from test page for someEvent'});
    7. vm.eventChannel.emit('getEditCompleteImg', {data: res.tempFilePath});
    8. // 返回页面
    9. uni.navigateBack()
    10. }
    11. })

     清除重置按钮逻辑

    1. // 清除重新绘制
    2. let vm = this;
    3. console.log('重新绘制')
    4. // 重新绘制图片 targetImgUrl为原先图片的url editWidth是canvas的宽度
    5. vm.drawContext.drawImage(vm.targetImgUrl,0,0,vm.editWidth,vm.editHeight)
    6. vm.drawContext.draw()
    7. // 重新设置颜色 这是封装的一个方法,画笔颜色宽度什么的
    8. vm.updateDrawContext()

    在mounted中拿到canvas的宽度,高度在拿到图片的高度宽度信息获取宽高比后,动态设置高度。

    1. uni.createSelectorQuery().in(this).select(canvas元素设置的类名).boundingClientRect(data => {
    2. // console.log(JSON.stringify(data))
    3. // {"id":"","dataset":{},"left":12,"right":308,"top":12,"bottom":315,"width":296,"height":303}
    4. // this.editHeight = data.height
    5. this.editWidth = data.width
    6. console.log('读取到的',this.editWidth)
    7. }).exec()

    在onLoad里面获取图片的url,然后获取图片的高度和宽度存到data中。

    1. const ctx = uni.createCanvasContext(canvas元素设置的id值)
    2. // 设置线条
    3. this.drawContext = ctx
    4. let vm = this
    5. vm.eventChannel.on('acceptDataFromOpenerPage', function(data) {
    6. console.log(data)
    7. vm.targetImgUrl = data.data
    8. // 获取图片的宽高
    9. uni.getImageInfo({
    10. src: data.data,
    11. success: function (image) {
    12. vm.initImgWidth = image.width;
    13. vm.initImgHeight = image.height;
    14. console.log('图片高度:',vm.initImgHeight)
    15. console.log('图片宽度:',vm.initImgWidth)
    16. console.log('图片纵横比',image.width/image.height)
    17. // 避免图片拉伸,保持纵横比
    18. const widthHeight = image.height/image.width
    19. vm.editHeight = widthHeight*vm.editWidth
    20. console.log('画布的高度',vm.editHeight)
    21. console.log('画布的宽度',vm.editWidth)
    22. vm.drawContext.drawImage(data.data,0,0,vm.editWidth,vm.editHeight)
    23. vm.drawContext.draw()
    24. // 设置画笔颜色
    25. vm.updateDrawContext()
    26. },
    27. error: function (err) {
    28. console.log(err)
    29. },
    30. complete:function(end){
    31. console.log(end)
    32. }
    33. });
    34. })

    导航栏返回和底部手机返回键

    在onBackPress中设置

    图片涂鸦绘制逻辑 

    在getImageInfo中,已经将图片绘制到canvas中。剩下的就是设置canvas的开始触摸事件,触摸滑动事件,触摸结束事件等。

    具体逻辑可以看这篇文章,canvas签名的逻辑,也是参考文章中的链接: 

    uniapp中使用canvas - 小兔儿_乖乖 - 博客园

    1. touchstart: function (e) {
    2. // 取出x、y的值
    3. let {
    4. x,
    5. y
    6. } = e.changedTouches[0]
    7. // 绘制线条起点
    8. this.drawContext.beginPath()
    9. this.drawContext.moveTo(x, y)
    10. // 起点与移动的连接断开
    11. this.moveX = ''
    12. this.moveY = ''
    13. },
    14. touchmove: function (e) {
    15. // 取出x, y的值
    16. let {
    17. x,
    18. y
    19. } = e.changedTouches[0]
    20. // 防止线条出现断点
    21. if (this.moveX && this.moveY) {
    22. this.drawContext.moveTo(this.moveX, this.moveY)
    23. this.drawContext.lineTo(this.moveX, this.moveY)
    24. }
    25. this.drawContext.lineTo(x, y)
    26. this.moveX = x
    27. this.moveY = y
    28. this.drawContext.stroke()
    29. // ture,保留之前的内容
    30. this.drawContext.draw(true)
    31. },

     

  • 相关阅读:
    spring 配置文件 --bean
    【Linux】Crontab、Shell、Linux、Git
    vue组件间通信的四种方法
    专利申请流程详解
    SpringCloud链路追踪——Spring Cloud Sleuth 和 Zipkin 介绍 & Windows 下使用初步
    Python第二语言(三、Python函数def)
    SysTick—系统定时器
    石油、化工 工程上都在用的地下管线探测仪---TFN A1200
    Win11的22H2依然没有WSA(Windows Subsystem for Android)?
    深入理解JMM
  • 原文地址:https://blog.csdn.net/GhostPaints/article/details/128190868