共计 3380 个字符,预计需要花费 9 分钟才能阅读完成。
第一种(较简单)
- 依据图片门路获取图片数据,转成 blob 类型
- 用
FileReader
读取图片 blob 数据为 dataURL - 创立 img 标签,src 属性为 dataURL
- 监听
img.onload
, 创立 canvas, 将 img 对象draw
在 canvas 里 - 增加水印
- 应用
canvas.toBlob
转成最终图像
代码
- async/await 版
/**
*
* @param {图片门路} imgUrl
* @param {图片宽度} width
* @param {图片高度} height
* @param {水印文字} watermarkText
*/
async function watermark(
imgUrl,
width = 300,
height = 300,
watermarkText = "zpfei.ink"
) {
// 1. 依据图片门路获取图片数据,转成 blob 类型
const fileBlob = await fetch(imgUrl)
.then((r) => r.blob())
.then((file) => file);
// 2. 用 `FileReader` 读取图片 blob 数据为 dataURL
const reader = new FileReader();
reader.readAsDataURL(fileBlob);
// 3. 创立 img 标签,src 属性为 dataURL
const tempImg = await new Promise((resolve) => {reader.onload = () => {const img = document.createElement("img");
img.src = reader.result;
resolve(img);
};
});
// 4. 监听 `img.onload`, 创立 canvas, 将 img 对象 `draw` 在 canvas 里
const canvas = await new Promise((resolve) => {const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
tempImg.onload = () => {const ctx = canvas.getContext("2d");
ctx.drawImage(tempImg, 0, 0);
// 5. 增加水印
ctx.fillStyle = "red";
ctx.textBaseline = "middle";
ctx.fillText(watermarkText, 20, 20);
resolve(canvas);
};
});
// 6. 应用 `canvas.toBlob` 转成最终图像
const newImg = await new Promise((resolve) => {canvas.toBlob((canvasBlob) => {const newImg = document.createElement("img"),
url = URL.createObjectURL(canvasBlob);
newImg.onload = function () {
// 图片加载实现后销毁 objectUrl
URL.revokeObjectURL(url);
};
newImg.src = url;
resolve(newImg);
});
});
// document.body.appendChild(newImg);
return newImg;
}
- 惯例回调版
const imgUrl =
"https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg";
fetch(imgUrl)
.then((r) => r.blob())
.then((file) => {const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 400;
const img = document.createElement("img");
img.src = reader.result;
img.onload = () => {const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
ctx.fillStyle = "red";
ctx.textBaseline = "middle";
ctx.fillText("zpfei.ink", 20, 20);
canvas.toBlob((canvasBlob) => {const newImg = document.createElement("img"),
url = URL.createObjectURL(canvasBlob);
newImg.onload = function () {
// 图片加载实现后销毁 objectUrl
URL.revokeObjectURL(url);
};
newImg.src = url;
document.body.appendChild(newImg);
});
};
};
});
第二种(简略)
- 图片门路转成 canvas
- canvas 增加水印
- canvas 转成 img
代码
/**
* 图片门路转成 canvas
* @param {图片 url} url
*/
async function imgToCanvas(url) {
// 创立 img 元素
const img = document.createElement("img");
img.src = url;
img.setAttribute("crossOrigin", "anonymous"); // 避免跨域引起的 Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
await new Promise((resolve) => (img.onload = resolve));
// 创立 canvas DOM 元素,并设置其宽高和图片一样
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
// 坐标(0,0) 示意从此处开始绘制,相当于偏移。canvas.getContext("2d").drawImage(img, 0, 0);
return canvas;
}
/**
* canvas 增加水印
* @param {canvas 对象} canvas
* @param {水印文字} text
*/
function addWatermark(canvas, text) {const ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.textBaseline = "middle";
ctx.fillText(text, 20, 20);
return canvas;
}
/**
* canvas 转成 img
* @param {canvas 对象} canvas
*/
function convasToImg(canvas) {
// 新建 Image 对象,能够了解为 DOM
var image = new Image();
// canvas.toDataURL 返回的是一串 Base64 编码的 URL
// 指定格局 PNG
image.src = canvas.toDataURL("image/png");
return image;
}
// 运行示例
async function run() {
const imgUrl =
"https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg";
// 1. 图片门路转成 canvas
const tempCanvas = await imgToCanvas(imgUrl);
// 2.canvas 增加水印
const canvas = addWatermark(tempCanvas, "zpfei.ink");
// 3.canvas 转成 img
const img = convasToImg(canvas);
// 查看成果
document.body.appendChild(img);
}
正文完
发表至: javascript
2020-07-13