第一步
找到一张模板图,如下:
这是一张通过rgba的b通道区分的模板图,每个碎片的b通道,对应序号分别是0,10,20,30,40,……
即序号的10倍等于b通道的值。
第二步
找到一张需要切分的图,如下:
确保两张图的尺寸一致,不一致会导致压缩变形既。
第三步
上代码,微信小程序: ts代码:
// components/cut-img/index.ts component({ /** * 组件的属性列表 */ properties: { temp: { type: string, value: getapp().imgprefix('/model/test/temp5-3.png') }, img: { type: string, value: getapp().imgprefix('/model/test/test.jpg') }, size: { type: number, value: 15 }, }, /** * 组件的初始数据 */ data: { }, lifetimes: { ready() { // 通过 selectorquery 获取 canvas 节点 settimeout(() => { const query = wx.createselectorquery().in(this) query.select('#canvas') .fields({ node: true, size: true, }) .exec(this.init.bind(this)) }, 1000); }, }, /** * 组件的方法列表 */ methods: { /** * 初始化 */ init(res: any) { const canvas = this.canvas = res[0]?.node if (!canvas) { return false } this.ctx = canvas.getcontext('2d') this.settemp() return false }, /** * 设置temp 图片上图 */ settemp() { const ctx = this.ctx const canvas = this.canvas const img = canvas.createimage() ctx.clearrect(0, 0, canvas.width, canvas.height) img.onload = () => { this.width = canvas.width = img.width this.height = canvas.height = img.height ctx.drawimage(img, 0, 0, canvas.width, canvas.height) this.tempdata = ctx.getimagedata(0, 0, canvas.width, canvas.height); this.setimg() } img.src = this.data.temp }, /** * 设置img 图片上图 */ setimg() { const ctx = this.ctx const canvas = this.canvas const img = canvas.createimage() ctx.clearrect(0, 0, canvas.width, canvas.height) img.onload = () => { ctx.drawimage(img, 0, 0, canvas.width, canvas.height) this.imgdata = ctx.getimagedata(0, 0, canvas.width, canvas.height); const size = this.data.size const list: any[] = [] for(let i = 0; i < size; i++) { this.cut(i, list) } console.log('>>> list', list) // this.triggerevent('success', list) } img.src = this.data.img }, /** * 裁剪 * @param index 序号 * @param list 存储列表 */ cut(index: number, list: any[]) { const ctx = this.ctx const canvas = this.canvas const newdata = ctx.createimagedata(this.width, this.height); for (let i = 0; i < newdata.data.length; i += 4) { const temp = this.tempdata.data.slice(i, i + 4) if (math.abs(temp[2] - index * 10) < 2 && temp[3] > 10) { newdata.data[i + 0] = this.imgdata.data[i + 0] newdata.data[i + 1] = this.imgdata.data[i + 1] newdata.data[i + 2] = this.imgdata.data[i + 2] newdata.data[i + 3] = this.imgdata.data[i + 3] } else { newdata.data[i + 0] = 0 newdata.data[i + 1] = 0 newdata.data[i + 2] = 0 newdata.data[i + 3] = 0 } } // ctx.putimagedata(newdata, 0, 0) let minx = newdata.width; let miny = newdata.height; let maxx = -1; let maxy = -1; // 遍历所有像素,查找非透明像素的位置 for (let y = 0; y < newdata.height; y++) { for (let x = 0; x < newdata.width; x++) { const pixelindex = (y * newdata.width + x) * 4; if (newdata.data[pixelindex + 3] > 0) { // alpha通道大于0表示非透明 minx = math.min(minx, x); maxx = math.max(maxx, x); miny = math.min(miny, y); maxy = math.max(maxy, y); } } } const width = maxx - minx + 1 const height = maxy - miny + 1 canvas.width = width canvas.height = height // 创建新的图像数据对象用于裁剪后的图像 const croppedimage = ctx.createimagedata(width, height); // 复制非透明像素到新的图像数据中 for (let y = miny; y <= maxy; y++) { for (let x = minx; x <= maxx; x++) { const srcindex = ((y * newdata.width) + x) * 4; const destindex = ((y - miny) * (maxx - minx + 1) + (x - minx)) * 4; croppedimage.data.set(newdata.data.subarray(srcindex, srcindex + 4), destindex); } } // 清除画布并绘制裁剪后的图像 ctx.clearrect(0, 0, width, height); ctx.putimagedata(croppedimage, 0, 0); const dataurl = canvas.todataurl('image/png'); list.push({ x: minx, y: miny, width, height, dataurl }) }, } })
wxml代码:
<!--components/cut-img/index.wxml--> <view style="display: none;"> <canvas type="2d" id="canvas"></canvas> </view>
步骤总结
1、获取canvas
2、先渲染模板,拿到模板图的imgdata
3、再渲染需要切换的目标图,拿到目标图的imgdata
4、根据切分的数量,循环切分
4.1、创建一个空的imgdata,根据序号对应的b通道,把对应的切片数据存入imgdata
4.2、计算非空白区域的位置和尺寸,裁剪图片数据
4.3、裁剪后的数据放回canvas,导出dataurl
4.4、保存对应的x、y、width、height、dataurl
5、返回list
到此这篇关于javascript前端实现拼图分割效果的文章就介绍到这了,更多相关javascript拼图分割内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论