Как реализовать обрезку изображения в апплете WeChat? Воспользуйтесь кодом, спасибо!

Апплет WeChat

Обзор прошлой ситуации

мой предыдущий пост《如何实现微信小程序换头像?三步帮你搞定! 》, упомянул, что для изменения аватара апплета WeChat требуется три шага:

  1. Получить аватар пользователя
  2. шаблон изображения
  3. синтез изображений

В предыдущей статье были описаны два этапа получения аватара пользователя и шаблона изображения, а в этой статье подробно объясняется, как синтезировать изображения.

Очень важной функцией в процессе синтеза изображения является вырезание изображения. Функциональная точка очень фиксированная.Большинство картинок перетаскиваются и масштабируются, а затем картинка с фиксированной длиной и шириной вырезается в определенной области. В приложении и H5 есть много зрелых плагинов для такого рода функций.Далее давайте посмотрим, как реализован плагин вырезания аватара в апплете Dolphin Funtu.Комментарии приветствуются.

Чтобы лучше понять следующий код, рекомендуется сначала отсканировать и испытать эффект обрезки изображения.

海豚趣图

добиться эффекта

实现效果

реализация интерфейса

В 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: {
  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>Перерисуйте область отсечения изображения, сохраните его во временном каталоге WeChat и вернитесь к пути сохранения. Следует отметить, что положение отсечения записанного изображения после перетаскивания и масштабирования не является положением исходного изображения.canvasизdrawImageПри рисунке ему необходимо преобразовать в исходное положение изображения или сначалаcanvasСистема координат масштабируется.Примечание. Вызывается в пользовательском компоненте.wx.createCanvasContext(string canvasId, Object this)метод, второй параметр this нельзя опускать, иначе рисунок холста не будет реагировать

/**
  * 图片剪切入口方法
  */
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>Значение демпфирования должно быть установлено в верхнем регистре, иначе оно может быть перетащено за пределы
  • Вызывается под пользовательским компонентомwx.createCanvasContext(string canvasId, Object this)метод, второй параметр this нельзя опускать, иначе рисунок холста не будет реагировать
  • Не забудьте преобразовать в фактический размер изображения при вырезании изображения.

насчет нас

Передовая команда Kuaigou Taxi занимается обменом передовыми технологиями и регулярно публикует высококачественные статьи. Добро пожаловать, обратите внимание и лайкните. Статья будет опубликована в паблике одновременно, если вы хотите получать актуальную информацию как можно быстрее, просто отсканируйте ее!

公众号二维码