此代码功能原用于已上线的图片圈子小程序 — 创艺有图,不过很可惜,目前该小程序已下线,下面是完整代码的展现效果图:

功能是用户选择手机里的图片后可以拖动位置进行方块功能裁剪,有九宫格和四宫格,裁剪是一键完成的,而且很快,但不支持缩放。

点击裁剪按钮后会跳到裁剪后的图片格子页,在这页中可以选择单张保存或是一键保存;和网页中不一样,一件保存是微信小程序的特有功能,不必制成压缩包,很方便;下面是步骤拆分:
- 使用了微信小程序组件 movable-area、movable-view
- 待剪图片上的网格和遮罩是通过元素标记加样式表组成的
- 使用微信小程序组件 canvas 和其相关的 API 实现的裁剪
- 裁剪完后以本地的临时图像显示在图片元素里
裁剪关键代码:
var that = this
var selected_counts = that.data.selected_counts
var column = selected_counts == 4 ? 2 : 3
var short_width = that.data.pic_width <= that.data.pic_height ? that.data.pic_width : that.data.pic_height
const query = wx.createSelectorQuery()
query.select(''#myCanvas'')
.fields({
node: true,
size: true
})
.exec((res2) => {
const canvas = res2[0].node
const ctx = canvas.getContext(''2d'')
var cut_width = short_width / column
canvas.width = cut_width
canvas.height = cut_width
var cut_x_start = Math.abs(that.data.trans_x)
cut_x_start = that.data.scale_ratio < 1 ? cut_x_start / that.data.scale_ratio : cut_x_start * that.data.scale_ratio
var cut_y_start = Math.abs(that.data.trans_y)
cut_y_start = that.data.scale_ratio < 1 ? cut_y_start / that.data.scale_ratio : cut_y_start * that.data.scale_ratio
const headerImg = canvas.createImage();
headerImg.src = that.data.local_pic_url;
headerImg.onload = () => {
var pictures_cuted = that.data.pictures_cuted
pictures_cuted = []
that.setData({
pictures_cuted: pictures_cuted
})
var cut_x = cut_x_start
var cut_y = cut_y_start
for (var i = 1; i <= selected_counts; i++) {
ctx.drawImage(headerImg, cut_x, cut_y, cut_width, cut_width, 0, 0, cut_width, cut_width);
if (i % column == 0) {
cut_x = cut_x_start
cut_y += cut_width
} else {
cut_x += cut_width
}
wx.canvasToTempFilePath({
fileType: "jpg",
quality: 0.9,
canvas: canvas,
success(res) {
var pictures_cuted = that.data.pictures_cuted
pictures_cuted.push(res.tempFilePath)
that.setData({
pictures_cuted: pictures_cuted
})
}
})
}
}
})
可以知道裁剪的原理是根据用户拖动的位置与图片的大小和网格的大小综合计算绘制出来的,这里面有部分参数如图片根据手机屏幕的缩放比、图片宽高等需要在加载图片的步骤中提前设置好。
九网格的标记代码是:
<view id="view_grids_box_9">
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
<view class="VIEW_grids"></view>
</view>
九宫格的样式表代码是:
#view_grids_box_9 {
border: 1px solid #fff;
box-sizing: border-box;
position: absolute;
width: 80vw;
height: 80vw;
top: calc(50% - 40vw);
left: 10vw;
pointer-events: none;
z-index: 100;
display: flex;
flex-wrap: wrap;
}
#view_grids_box_9 .VIEW_grids {
border: 1px dashed rgba(250, 250, 250, .5);
width: calc(100% / 3);
position: relative;
box-sizing: border-box;
}
标记与样式表配合就实现了图片上覆盖的网格效果。在微信小程序组件 movable-view 中需要绑定移动改变事件 bindchange="moveAreaChange" 用于监测并保存图片被拖动的位置:
moveAreaChange: function (e) {
this.setData({
trans_x: e.detail.x,
trans_y: e.detail.y
})
}
在微信小程序中提供了一个 API 是 wx.saveImageToPhotosAlbum,调用这个接口轻松实现一键全部保存。