实现思路
- 首先将原始图像微量平移8个方向
- 然后用描边颜色去填充移动后的图像
- 最后将原图叠加上去
核心代码
生成画布
这一步没什么说的,就是创建canvas,加载图片,设置canvas的宽高为图片宽高:
// create canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// create image
const image = new Image();
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
};
image.src = url;
image.crossOrigin = "Anonymous";
平移图像
我们构造一个数组,2个元素
表示一个方向
。
const dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1];
设置borderWidth
为4
,根据方向和borderWidth
,我们可以计算出平移后的x
,y
,
const borderWidth = 4;
const x = dArr[i] * borderWidth;
const y = dArr[i + 1] * borderWidth;
循环所有方向绘制原图:
for (let i = 0; i < dArr.length; i += 2) {
...
ctx.drawImage(image, x, y);
}
平移后的图像相当于原始图像向四周扩大了borderWidth
的距离。
填充描边色
这里我们需要用到globalCompositeOperation
中的source-in
模式
source-in
:在当前图像内绘制新图像,且只显示新图像。
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
绘制原图
将混合模式改为默认的source-over
,然后绘制原图:
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(image, 0, 0);
在线代码
完整代码
/**
* 图片描边
* @param {string} url - 图片地址或base64
* @param {string} [borderColor=red] - 描边颜色
* @param {number} [borderWidth=4] - 描边宽度
* @return {string} base64 - 描边后的图片字符串
*/
function strokeImage(url, borderColor='red', borderWidth = 4) {
return new Promise((resolve) => {
// create canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// create image
const image = new Image();
image.onload = draw;
image.src = url;
image.crossOrigin = "Anonymous";
function draw() {
canvas.width = image.width;
canvas.height = image.height;
const dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1]; // offset array
// 平移图像
for (let i = 0; i < dArr.length; i += 2)
ctx.drawImage(image, dArr[i] * borderWidth, dArr[i + 1] * borderWidth);
// 填充描边色
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = borderColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 添加原图
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(image, 0, 0);
resolve(canvas.toDataURL());
}
});
}