如何实现微信小程序图像剪切?代码拿去用,不谢!

简介: 我在早先发布的文章《如何实现微信小程序换头像?三步帮你搞定!》中,提到实现微信小程序换头像需要三步:获取用户头像图片模板图片合成前文已经就获取用户头像和图片模板两个步骤进行了讲解,本文就来详细说说如何合成图片。图片合成的过程中非常重要的一块功能对图片进行剪切。该功能点很固定,大都是对图片进行拖拽、缩放后,在一定区域内剪切出一个固定长宽的图片。这类功能在app端和H5中都有很多成熟的插件供使用,接下来就来看看我在海豚趣图小程序中的头像剪切插件是如何实现的,欢迎大家提意见。

实现效果



界面实现


在H5中要实现图片的拖拽和缩放需要一大坨代码,具体实现网上有很多。小程序实现就简单的多了,通过 <movable-area><movable-view> 就可以实现上述功能


<view class="clip-view">
  <!--
    clipHeight、clipWidth 分别为剪切框的高和宽
    imgHeight、imgWidth 分别对应图片的初始高和宽
    imgUrl 为剪切图片的url地址
  -->
  <movable-area class="moveare" style="height: {{clipHeight}}rpx; width: {{clipWidth}}rpx; ">
    <movable-view scale="true" scale-min="{{1}}" damping="1000" style="height: {{imgHeight}}px; width: {{imgWidth}}px; " direction="all" x="{{x}}" y="{{y}}" bindchange="_onChange" bindscale="_onScale">
      <image class="clip-img" src="{{imgUrl}}" />
    </movable-view>
  </movable-area>
  <!--剪切框 装饰用-->
  <view class="clip-box" style="height: {{clipHeight}}rpx; width: {{clipWidth}}rpx; ">
    <!--剪切框四个角-->
    <view class="clip-border clip-border-lt"></view>
    <view class="clip-border clip-border-rt"></view>
    <view class="clip-border clip-border-lb"></view>
    <view class="clip-border clip-border-rb"></view>
  </view>
  <!--剪切图片用的canvas-->
  <canvas class="clip-canvas" id="img_clip_canvas" canvas-id="img_clip_canvas" style="height: {{clipHeight}}rpx; width: {{clipWidth}}rpx; "></canvas>
</view>


组件属性


组件的入参只需要原始图片的地址和图片剪切框的宽高


/**
 * 组件的属性列表
 */
properties: {
  // 原始图片路径(要剪切的图片)
  imgUrl: {
    type: String,
    value: ''
  },
  // 剪切的宽度 (rpx)
  clipWidth: {
    type: Number,
    value: 500
  },
  // 截切的高度 (rpx)
  clipHeight: {
    type: Number,
    value: 500
  }
}


组件data


组件的data就会多一些记录图片拖拽缩放的数据,需要注意的是,图片初始位置和图片拖拽位置没有使用同一变量存储,是为了防止在拖拽过程中产生抖动。


/**
 * 组件的初始数据
 */
data: {
  baseScale: 1,
  imgPath: '',
  imgWidth: 0, // 图片宽
  imgHeight: 0, // 图片高
  x: 0, // 图片初始时x轴位置
  y: 0, // 图片初始时y轴位置,之所以不和top共用一个变量,是因为如果频繁改变y值,图片会闪烁,x同理
  left: 0, // 图片拖拽后的x轴位置
  top: 0, // 图片拖拽后的y轴位置
  scale: 1 // 拖拽后的缩放比例
}


组件初始化


组件的初始化方法用于把图片缩放到合适的大小,并使剪切框位于图片中央


/**
 * 初始化方法
 * 获取图片宽高后,把图片缩放至剪切框大小,
 * 并使剪切框位于图片中央
 **/
_init() {
  if (!this.data.imgUrl) return
  // 获取屏幕宽度
  let {
    screenWidth
  } = wx.getSystemInfoSync()
  // 计算屏幕rpx
  const rpx = screenWidth / 750
  // 获取图片宽高,然后缩放至剪切框大小
  wx.getImageInfo({
    src: this.data.imgUrl,
    success: ({
      width,
      height,
      path
    }) => {
      const cw = this.data.clipWidth * rpx
      const ch = this.data.clipHeight * rpx
      let scale = Math.max(cw / width, ch / height)
      const imgWidth = width * scale
      const imgHeight = height * scale
      this.setData({
        imgPath: path,
        imgWidth,
        imgHeight,
        baseScale: scale,
        x: (cw - imgWidth) / 2,
        y: (ch - imgHeight) / 2
      })
    }
  })
}


图片拖拽缩放处理


完成初始化后就可以监听用户的拖拽和缩放操作了,主要是记录拖拽的位置和缩放的比例,具体到代码实现就是监听<movable-view> 的拖拽(bindchange)和缩放(bindscale)事件


// 拖拽事件响应函数
  _onChange: function(e) {
    this.setData({
      x: e.detail.x,
      y: e.detail.y
    })
  }
  // 缩放事件响应函数
  _onScale: function(e) {
    this.setData({
      x: e.detail.x,
      y: e.detail.y,
      scale: e.detail.scale
    })
  }


图片剪切实现


拖拽缩放完成后就是剪切了,剪切是利用了<canvas>重新绘制图片的剪切区域,保存到微信临时目录里,并返回保存路径。需要注意的是拖拽和缩放后记录的图片剪切位置并不是原图的位置,利用canvasdrawImage 进行绘制的时候需要转换成原图位置,或者先把canvas的坐标系进行缩放。注意:在自定义组件下调用 wx.createCanvasContext(string canvasId, Object this)方法时,第二个参数this不能省略,否则canvas绘制无响应


/**
  * 图片剪切入口方法
  */
clip() {
  const scale = this.data._scale * this.data._baseScale
  const canvasId = 'img_clip_canvas'
  imageClip(canvasId, this.data.imgPath, {
    x: this.data._left * -1,
    y: this.data._top * -1,
    scale,
    width: this.data.clipWidth,
    height: this.data.clipHeight
  }, this)
}
/**
 * 图片剪切
 *
 * @param canvas canvas组件id,用于绘制剪切图片
 * @param img 要剪切的图片
 * @param option 剪切的位置宽高等信息
 * @param option.left 剪切图片左边距
 * @param option.top 剪切图片上边距
 * @param option.width 剪切图片宽度
 * @param option.height 剪切图片高度
 * @param context 组件实例对象
 * 
 * @return new Promise(resolve=>ctx)
 */
imageClip(canvas, img, option, context) {
  return new Promise((resolve, reject) => {
    option = Object.assign({
      left: 0,
      top: 0,
      scale: 1,
      width: 0,
      height: 0
    }, option)
    let x = option.left / option.scale
    let y = option.top / option.scale
    let clipW = option.width / option.scale
    let clipH = option.height / option.scale
    const ctx = wx.createCanvasContext(canvas, context)
    ctx.drawImage(img,
      x,
      y,
      clipW,
      clipH,
      0,
      0,
      option.width,
      option.height)
    ctx.draw(false, (e) => {
      console.log(e)
      resolve()
    })
  })
},
/**
 * canvas 保存为临时文件
 */
function saveCanvasToTemp(canvas, option) {
  return new Promise((resolve, reject)=>{
    wx.canvasToTempFilePath({
      ...option,
      canvasId: canvas,
      success:resolve,
      fail:reject
    }, this)
  })
}


写在最后


这就是小程序版图片剪切的主要代码实现,里面还有一些小点儿需要注意


  • <movable-view> 的damping的值要设置大写,否则可能会出现拖出界外的情况


  • 在自定义组件下调用 wx.createCanvasContext(string canvasId, Object this)方法时,第二个参数this不能省略,否则canvas绘制无响应


  • 切图时要记住转换成实际图片的大小


相关文章
|
3月前
|
存储 小程序 UED
微信小程序代码包限制2M 怎么解决?
微信小程序代码包限制2M 怎么解决?
|
3月前
|
Web App开发 监控 JavaScript
1号防红网:什么是微信防红不死短链接?微信防红不死短链接代码示例
1号防红网:什么是微信防红不死短链接?微信防红不死短链接代码示例
58 0
|
2天前
|
小程序
外卖小程序-购物车模块表结构设计和后端代码
外卖小程序-购物车模块表结构设计和后端代码
9 0
|
19天前
|
Linux 网络安全 开发工具
【超详细!超多图!】【代码管理】Python微信公众号开发(3)- 服务器代码上传Github
【超详细!超多图!】【代码管理】Python微信公众号开发(3)- 服务器代码上传Github
23 0
|
1月前
|
小程序 开发者
微信小程序“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?
微信小程序“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?
|
2月前
|
存储 小程序 前端开发
Java代码能搭建小程序
Java代码能搭建小程序
21 0
|
2月前
|
小程序
微信小程序下载代码
微信小程序下载代码
|
3月前
|
JavaScript 小程序
微信小程序的双向数据绑定和vue的哪里不一样?下拉刷新的方式代码示例
微信小程序的双向数据绑定和vue的哪里不一样?下拉刷新的方式代码示例
|
3月前
|
小程序 JavaScript 前端开发
【经验分享】如何实现小程序代码热更新| 江海计划
【经验分享】如何实现小程序代码热更新| 江海计划
56 6
|
3月前
|
小程序 JavaScript IDE
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
19 0

热门文章

最新文章