Canvas绘制图片合成样式
效果图
web
* {
margin: 0;
padding: 0;
}
.container {
position: relative;
width: 328px;
height: 328px;
margin: 100px auto;
}
.container img {
position: absolute;
width: 328px;
height: 328px;
}
#canvas {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
.img-shape-bg {
position: absolute;
top: 0;
left: 50%;
width: 284px;
height: 284px;
transform: translateX(-50%) scale(1.4);
opacity: .05;
}
<div class="container">
<img src="icosphere_red@2x.png" alt="">
<canvas id="canvas" width="140" height="140"></canvas>
<!-- 加一层背景模糊,优化背景色 -->
<view class="img-shape-bg" style="background-image: radial-gradient( circle, red 50%, transparent, transparent)"></view>
</div>
function mergeImages() {
// 创建一个画布
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const overlay = new Image();
// 蒙层及样版图片
overlay.src = "mask@2x.png";
overlay.onload = function () {
context.drawImage(overlay, 0, 0, 140, 140);
const template = new Image();
template.src = "1.png";
template.onload = function (res) {
let width = height = 140
let realWidth = template.width
let realHeight = template.height
let imgRatio = realWidth / realHeight
let sw = 0, sh = 0, sx = 0, sy = 0;
let canvasRatio = width / height
// 图片不变形
if(imgRatio <= canvasRatio) {
sw = realWidth
sh = sw / canvasRatio
sx = 0
sy = (realHeight - sh) / 2
} else {
sh = realHeight
sw = sh * canvasRatio
sx = (realWidth - sw) / 2
sy = 0
}
// 仅在新形状和目标画布重叠的地方绘制新形状。其他的都是透明的
context.globalCompositeOperation = "source-in";
context.drawImage(template, sx, sy, sw, sh, 0, 0, 140, 140);
};
};
}
mergeImages()
miniprogram
.note-top-shape {
box-sizing: border-box;
position: relative;
width: 284rpx;
height: 284rpx;
margin: auto;
.img-shape-main {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -52%);
width: 120rpx;
height: 120rpx;
z-index: 2;
}
.img-shape {
position: relative;
z-index: 1;
}
.img-shape-bg {
position: absolute;
top: 0;
left: 50%;
width: 284rpx;
height: 284rpx;
transform: translateX(-50%) scale(1.5);
opacity: .05;
}
}
// 水晶
<view class="note-top-shape">
<image class="img-shape" src="{{ baseImageUrl }}{{ kindShape }}" mode="aspectFit" lazy-load="false" style="width: 284rpx;height: 284rpx;" binderror="" bindload="" />
// canvas 在上面显示,因为canvas在小程序中层级太高,所以需要转化为image src展示
<canvas type="2d" id="canvas_{{listItem.id}}" style="position: fixed;top: -9999px;left: -9999px;width: 240rpx;height: 240rpx;"></canvas>
<block>
<image class="img-shape-main" src="{{ imgPath }}" mode="aspectFit" lazy-load="false" binderror="" bindload=""></image>
</block>
// 加一层背景模糊
<view class="img-shape-bg" style="background-image: radial-gradient( ellipse at top, {{ listItem.style }} 50%, transparent, transparent)"></view>
</view>
Component({
properties: {
listItem: {
type: Object,
default: {
//shape: 0,
//style: red,
}
}
},
observers: {
'listItem': function(item) {
let shape = item.shape
var shapeImage = ''
switch (shape) {
case '0':
shapeImage = 'pyramid'
break
case '1':
shapeImage = 'cube'
break
case '2':
shapeImage = 'diamond'
break
case '3':
shapeImage = 'hexsphere'
break
case '4':
shapeImage = 'icosphere'
break
}
// 水晶图片是根据接口数据显示的
let src = `shape/${shapeImage}_${item.style}@2x.png`
this.setData({
kindShape: src
})
}
},
data: {
imgPath: ''
},
attached() {
let item = this.data.listItem
this.mergeImagesMiniProgram(item.id, '/assets/images/mask@2x.png', item.photos[0])
},
methods: {
mergeImagesMiniProgram(id, maskPath, filePath) {
let that = this
let query = wx.createSelectorQuery().in(this)
query.select(`#canvas_${id}`).fields({ node: true, size: true }).exec((rescanvas) => {
let canvas = rescanvas[0].node
let ctx = canvas.getContext('2d')
const overlay = canvas.createImage()
overlay.src = maskPath
let width = canvas.width = 120
let height = canvas.height = 120
let canvasRatio = width / height
overlay.onload = function () {
ctx.drawImage(overlay, 0, 0, width, height)
const template = canvas.createImage()
template.src = filePath
template.onload = function () {
let realWidth = template.width
let realHeight = template.height
// cover
let imgRatio = realWidth / realHeight
let sw = 0, sh = 0, sx = 0, sy = 0;
if(imgRatio <= canvasRatio) {
sw = realWidth
sh = sw / canvasRatio
sx = 0
sy = (realHeight - sh) / 2
} else {
sh = realHeight
sw = sh * canvasRatio
sx = (realWidth - sw) / 2
sy = 0
}
// ctx.globalCompositeOperation = "destination-in";
ctx.globalCompositeOperation = "source-in";
ctx.drawImage(template, sx, sy, sw, sh, 0, 0, width, height)
// ctx.drawImage(template, 0, 0, width, height);
wx.canvasToTempFilePath({
canvas,
width: width,
height: height,
destWidth: width * app.globalData.pixelRatio,
destHeight: height * app.globalData.pixelRatio,
success: async function(res) {
let filePath = res.tempFilePath;
that.setData({
imgPath: filePath
})
},
fail: function (res) {
}
})
}
}
})
}
})
素材图片
水晶
蒙层
我不叫胖虎
有需要可+qq:2091545890
参考文档-canvas drawImage绘图实现contain和cover的效果
参考文档-CanvasRenderingContext2D