微信小程序之裁剪图片成圆形的实现代码


Posted in Javascript onOctober 11, 2018

前言

最近在开发小程序,产品经理提了一个需求,要求微信小程序换头像,用户剪裁图片必须是圆形,也在github上看了一些例子,一般剪裁图片用的都是方形,所以自己打算写一个小组件,可以把图片剪裁成圆形,主要思路就是使用canvas绘图,把剪裁的图片绘制成圆形,另外剪裁图片的窗口还可以移动放大缩小,这个功能就用了微信组件movable-view,好了,该说的也说完了,下面咱们开始撸代码。

movable-view组件

可移动的视图容器,在页面中可以拖拽滑动

会有好多个属性,在这里不一一介绍,只说我们能用到的就可以。

我们用到的属性主要有:

1.direction:movable-view的移动方向,属性值有all、vertical、horizontal、none

2.scale:是否支持双指缩放,默认缩放手势生效区域是在movable-view内

3.scale-min 定义缩放倍数最小值

4.scale-max 定义缩放倍数最大值

5.bindchange 拖动过程中触发的事件,event.detail = {x: x, y: y, source: source},其中source表示产生移动的原因,值可为touch(拖动)、touch-out-of-bounds(超出移动范围)、out-of-bounds(超出移动范围后的回弹)、friction(惯性)和空字符串(setData)

6.bindscale 缩放过程中触发的事件,event.detail = {x: x, y: y, scale: scale},其中x和y字段在2.1.0之后开始支持返回

主要用到的就是这几个值

另外使用movable-view的时候必须在外边加一个movable-area的父元素,不然的话没有移动区域。

movable-view 的可移动区域,属性只有:

scale-area 当里面的movable-view设置为支持双指缩放时,设置此值可将缩放手势生效区域修改为整个movable-area,是个boolean值,默认false

截取区域的移动已经说完了,详情请看传送门

canvas绘图

画布。该组件是原生组件可以绘制图像,分享朋友圈生成海报就经常用到这个属性,就简单的说下:

在wxml中必须要有canvas这个标签,才可以绘制图像,而且要有canvas-id属性,代表canvas 组件的唯一标识符,
还有许多API我就不一一介绍了,底下用的API代码当中都会用注释。详情请看微信小程序画布API传送门

代码实现

1.首先是选择图片

wxml就是初始化一个按钮点击的时候选择图片,而且需要引入我们封装的截取图片组件,并把图片作为参数传进去,封装组件方法请看我另一篇文章组件封装

index.wxml

Tip: 必须把canvas放到引入剪裁组件的wxml中,否则绘制不成功,因为canvas是原生组件脱离在 WebView 渲染流程外。

<view class="container">
 <button wx:if="{{!imgSrc}}" bindtap="getImgurl"> 选择图片 </button>
 <view class="clip-box" wx:if="{{imgSrc}}">
  <ClipImg imgSrc="{{imgSrc}}"></ClipImg>
 </view>
</view>
<canvas canvas-id="myCanvas" style="position:absolute; width:100%;height:100%;border: 1px solid red;left: -9999px; top: -9999px;"></canvas>

index.json引入截取图片的组件

{
 "component": true,
 "usingComponents": {
  "ClipImg": "../../component/clipImg/clipImg"
 }
}

index.js上传图片显示

const app = getApp()

Page({
 data: {
 imgSrc: ''
 },
 //选择图片
 getImgurl: function () {
 wx.chooseImage({
  count: 1, // 默认9
  sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
  sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
  success: (res) => {
  // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
  const tempFilePaths = res.tempFilePaths;
  //启动上传等待中... 
  wx.showToast({ 
   title: '正在上传...', 
   icon: 'loading', 
   mask: true, 
   duration: 1000 
  }) 
  this.setData({
   imgSrc: res.tempFilePaths
  })
  }
 })
 },
 onLoad: function () {
 }
})

接下来就是剪裁图片组件的封装

首先是页面布局,也就是clipImg.wxml

<view class="clip">
 <image class="head-img" style="width:{{cropperW}}rpx;height:{{cropperH}}rpx" src="{{imageUrl}}"></image>
 <movable-area scale-area style="width:{{cropperW}}rpx;height:{{cropperH}}rpx">
  <movable-view bindchange="move" bindscale="scale" direction="all" scale scale-min="0.5" scale-max="1.8">
  </movable-view>
 </movable-area>
 <view class="btn">
  <text bindtap="cancel">取消</text>
  <text bindtap="getImageInfo">保存</text>
 </view>
</view>

大概就是这个样子

微信小程序之裁剪图片成圆形的实现代码

上边的圆就是截取就是截取框。

然后就是clipImg.js文件主要就是对图片截取的一些操作

Component({
 /**
 * 组件的属性列表
 */
 properties: {
 imgSrc: {
  type: 'String',
  value: ''
 }
 },
 /**
 * 组件的初始数据
 * imageUrl string 初始化图片
 * cropperW string 缩小图宽度
 * cropperH string 缩小图高度,
 * img_ratio string 图片比例,
 * IMG_W string 原图高度,
 * IMG_H string 原图高度,
 * left string 图片距离左边距离,
 * top string 图片距离上边距离,
 * clipW number 默认截取框
 */
 data: {
 imageUrl: '',
 cropperW: '',
 cropperH: '',
 img_ratio: '',
 IMG_W: '',
 IMG_H: '',
 left: '',
 top: '',
 clipW: 200
 },
 /**
 * 组件的方法列表
 */
 methods: {
 //点击取消
 cancel: function () {
  var myEventDetail = {} // detail对象,提供给事件监听函数
  var myEventOption = {} // 触发事件的选项
  this.triggerEvent('myevent', myEventDetail, myEventOption)
 },
 //拖拽事件
 move: function ({ detail }) {
  this.setData({
  left: detail.x * 2,
  top: detail.y * 2
  })
 },
 //缩放事件
 scale: function ({ detail }) {
  console.log(detail.scale)
  this.setData({
  clipW: 200 * detail.scale
  })
 },
 //生成图片
 getImageInfo: function () {
  wx.showLoading({
  title: '图片生成中...',
  })
  const img_ratio = this.data.img_ratio;
  //要截取canvas的宽
  const canvasW = (this.data.clipW / this.data.cropperW) * this.data.IMG_W
  //要截取canvas的高
  const canvasH = (this.data.clipW / this.data.cropperH) * this.data.IMG_H
  //要截取canvas到左边距离
  const canvasL = (this.data.left / this.data.cropperW) * this.data.IMG_W
  //要截取canvas到上边距离
  const canvasT = (this.data.top / this.data.cropperH) * this.data.IMG_H
  // 将图片写入画布
  const ctx = wx.createCanvasContext('myCanvas');
  //绘制图像到画布
  ctx.save(); // 先保存状态 已便于画完圆再用  
  ctx.beginPath(); //开始绘制 
  ctx.clearRect(0, 0, 1000, 1000)
  //先画个圆  
  ctx.arc(this.data.clipW / 2, this.data.clipW / 2, this.data.clipW / 2, 0, 2 * Math.PI, false)
  ctx.clip();//画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 
  ctx.drawImage(this.data.imageUrl, canvasL, canvasT, canvasW, canvasH, 0, 0, this.data.clipW, this.data.clipW); // 推进去图片  
  ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 可以继续绘制
  ctx.draw(true, () => {
  // 获取画布要裁剪的位置和宽度 
  wx.canvasToTempFilePath({
   x: 0,
   y: 0,
   width: this.data.clipW,
   height: this.data.clipW,
   destWidth: this.data.clipW,
   destHeight: this.data.clipW,
   quality: 0.5,
   canvasId: 'myCanvas',
   success: (res) => {
   wx.hideLoading()
   /**
    * 截取成功后可以上传的服务端直接调用
    * wx.uploadFile();
    */
   //成功获得地址的地方
   wx.previewImage({
    current: '', // 当前显示图片的http链接
    urls: [res.tempFilePath] // 需要预览的图片http链接列表
   })
   }
  })
  })
 }
 },
 ready: function () {
 this.setData({
  imageUrl: this.data.imgSrc[0]
 })
 //获取图片宽高
 wx.getImageInfo({
  src: this.data.imageUrl,
  success: (res) => {
  console.log('图片信息', res);
  //图片实际款高
  const width = res.width;
  const height = res.height;
  //图片宽高比例
  const img_ratio = width / height
  this.setData({
   img_ratio,
   IMG_W: width,
   IMG_H: height,
  })
  if (img_ratio >= 1) {
   //宽比较大,横着显示
   this.setData({
   cropperW: 750,
   cropperH: 750 / img_ratio,
   })
  } else {
   //竖着显示
   this.setData({
   cropperW: 750 * img_ratio,
   cropperH: 750
   })
  }
  } 
 })
 }
})

到现在为止一个截取图片就完成了,可能会有些问题,比如截取的图片的框没有居中,自己可以再次封装这个组件,因为现在已经适合我们公司自己项目了。我们来预览下。另外这个组件支持双指放大截取框来截取图片,不过微信开发者工具不能展示,自己可以把代码下载下来,在自己手机上扫码查看效果。

微信小程序之裁剪图片成圆形的实现代码

另外我把项目放到了github上边,希望小哥哥小姐姐们多多点赞,多多支持,有什么疑问可以在github上问我,谢谢。点赞的小哥哥小姐姐最可爱,哈哈哈。。。

项目地址链接描述

推荐:

感兴趣的朋友可以关注小编的微信公众号【码农那点事儿】,更多网页制作特效源码及学习干货哦!!!

总结

以上所述是小编给大家介绍的微信小程序之裁剪图片成圆形的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
给jqGrid数据行添加修改和删除操作链接(之一)
Nov 04 Javascript
JS控制图片翻转示例代码(兼容firefox,ie,chrome)
Dec 19 Javascript
取消选中单选框radio的三种方式示例介绍
Dec 23 Javascript
javascript模拟map输出与去除重复项的方法
Feb 09 Javascript
JS获取短信验证码倒计时的实现代码
May 22 Javascript
关于jquery form表单序列化的注意事项详解
Aug 01 jQuery
Extjs 中的 Treepanel 实现菜单级联选中效果及实例代码
Aug 22 Javascript
vue-cli 打包使用history模式的后端配置实例
Sep 20 Javascript
vue中引入mxGraph的步骤详解
May 17 Javascript
ES6 Promise对象概念及用法实例详解
Oct 15 Javascript
微信小程序实用代码段(收藏版)
Dec 17 Javascript
JavaScript实现世界各地时间显示
Sep 07 Javascript
Vue中使用ElementUI使用第三方图标库iconfont的示例
Oct 11 #Javascript
css配合JavaScript实现tab标签切换效果
Oct 11 #Javascript
vue最简单的前后端交互示例详解
Oct 11 #Javascript
JavaScript中七种流行的开源机器学习框架
Oct 11 #Javascript
用Object.prototype.toString.call(obj)检测对象类型原因分析
Oct 11 #Javascript
使用vue 国际化i18n 实现多实现语言切换功能
Oct 11 #Javascript
详解Angular5/Angular6项目如何添加热更新(HMR)功能
Oct 10 #Javascript
You might like
JAVA/JSP学习系列之二
2006/10/09 PHP
require(),include(),require_once()和include_once()区别
2008/03/27 PHP
PHP分多步骤填写发布信息的简单方法实例代码
2012/09/23 PHP
php删除文件夹及其文件夹下所有文件的函数代码
2013/01/23 PHP
php过滤html中的其他网站链接的方法(域名白名单功能)
2014/04/24 PHP
PHP实现的通过参数生成MYSQL语句类完整实例
2016/04/11 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
PHP 扩展Memcached命令用法实例总结
2020/06/04 PHP
Javascript中eval函数的使用方法与示例
2007/04/09 Javascript
jQuery Validation插件remote验证方式的Bug解决
2010/07/01 Javascript
JavaScript获取网页支持表单字符集的方法
2015/04/02 Javascript
JS中捕获console.log()输出的方法
2015/04/16 Javascript
JS控制静态页面传递参数并获取参数应用
2016/08/10 Javascript
Javascript 闭包详解及实例代码
2016/11/30 Javascript
详解Jquery Easyui的验证扩展
2017/01/09 Javascript
JS 组件系列之 bootstrap treegrid 组件封装过程
2017/04/28 Javascript
Angular2使用Angular CLI快速搭建工程(一)
2017/05/21 Javascript
Angular4如何自定义首屏的加载动画详解
2017/07/26 Javascript
原生JS+Canvas实现五子棋游戏
2020/05/28 Javascript
详解在React中跨组件分发状态的三种方法
2018/08/09 Javascript
VUE在for循环里面根据内容值动态的加入class值的方法
2018/08/12 Javascript
跨域解决之JSONP和CORS的详细介绍
2018/11/21 Javascript
JS实现处理时间,年月日,星期的公共方法示例
2019/05/31 Javascript
vue中获取滚动table的可视页面宽度调整表头与列对齐(每列宽度不都相同)
2019/08/17 Javascript
vue中动态select的使用方法示例
2019/10/28 Javascript
H5实现手机拍照和选择上传功能
2019/12/18 Javascript
基于JavaScript实现留言板功能
2020/03/16 Javascript
react基本安装与测试示例
2020/04/27 Javascript
[46:27]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第一局
2016/03/02 DOTA
[02:36]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma 选手采访
2021/03/11 DOTA
python私有属性和方法实例分析
2015/01/15 Python
简单介绍Python的轻便web框架Bottle
2015/04/08 Python
Python 通过微信控制实现app定位发送到个人服务器再转发微信服务器接收位置信息
2019/08/05 Python
美术课外活动总结
2014/07/08 职场文书
2014年法院工作总结
2014/11/24 职场文书
会议主持人开场白台词
2015/05/28 职场文书