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


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 相关文章推荐
asp javascript 实现关闭窗口时保存数据的办法
Nov 24 Javascript
jQuery学习笔记(1)--用jQuery实现异步通信(用json传值)具体思路
Apr 08 Javascript
JavaScript避免内存泄露及内存管理技巧
Sep 05 Javascript
javascript学习笔记(五)原型和原型链详解
Oct 08 Javascript
JS中的THIS和WINDOW.EVENT.SRCELEMENT详解
May 25 Javascript
有关suggest快速删除后仍然出现下拉列表的bug问题
Dec 02 Javascript
使用UrlConnection实现后台模拟http请求的简单实例
Jan 04 Javascript
JS基于面向对象实现的多个倒计时器功能示例
Feb 28 Javascript
vue中如何实现变量和字符串拼接
Jun 19 Javascript
JS简单生成由字母数字组合随机字符串示例
May 25 Javascript
JavaScript引用类型Array实例分析
Jul 24 Javascript
详解如何给React-Router添加路由页面切换时的过渡动画
Apr 25 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
php学习笔记 面向对象中[接口]与[多态性]的应用
2011/06/16 PHP
CodeIgniter输出中文乱码的两种解决办法
2014/06/12 PHP
php格式化电话号码的方法
2015/04/24 PHP
浅谈php提交form表单
2015/07/01 PHP
PHP实现压缩图片尺寸并转为jpg格式的方法示例
2018/05/10 PHP
用javascript实现无刷新更新数据的详细步骤 asp
2006/12/26 Javascript
Raphael带文本标签可拖动的图形实现代码
2013/02/20 Javascript
JS获取计算机mac地址以及IP的实现方法
2014/01/08 Javascript
nodeJs爬虫获取数据简单实现代码
2016/03/29 NodeJs
JS简单获取客户端IP地址的方法【调用搜狐接口】
2016/09/05 Javascript
JS实现用户注册时获取短信验证码和倒计时功能
2016/10/27 Javascript
深入浅析Nodejs的Http模块
2017/06/20 NodeJs
RequireJS用法简单示例
2018/08/20 Javascript
Vuex 使用 v-model 配合 state的方法
2018/11/13 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
2019/06/12 Javascript
微信小程序自定义tabBar在uni-app的适配详解
2019/09/30 Javascript
js canvas实现星空连线背景特效
2019/11/01 Javascript
Node.js+Vue脚手架环境搭建的方法步骤
2020/03/08 Javascript
[01:06:07]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS CIS
2014/05/22 DOTA
python处理文本文件实现生成指定格式文件的方法
2014/07/31 Python
Python使用matplotlib实现在坐标系中画一个矩形的方法
2015/05/20 Python
对numpy Array [: ,] 的取值方法详解
2018/07/02 Python
python的concat等多种用法详解
2018/11/28 Python
python模式 工厂模式原理及实例详解
2020/02/11 Python
python爬虫使用正则爬取网站的实现
2020/08/03 Python
python+selenium 简易地疫情信息自动打卡签到功能的实现代码
2020/08/22 Python
PyQt5的QWebEngineView使用示例
2020/10/20 Python
JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
2013/07/02 面试题
下面代码从性能上考虑,有什么问题
2015/04/03 面试题
党支部对照检查材料
2014/08/25 职场文书
工资收入证明
2014/10/07 职场文书
2014年学习部工作总结
2014/11/12 职场文书
初中运动会前导词
2015/07/20 职场文书
2016新春团拜会致辞
2015/08/01 职场文书
严以律己专题学习研讨会发言材料
2015/11/09 职场文书
JS前端使用canvas实现物体的点选示例
2022/08/05 Javascript