-
在utils 创建一个watermark文件,里面包含index.js和watermark.js 两个js文件
index.js import _waterMark from './watermark';export function dataURLtoFile (dataurl, filename) { let arr = dataurl.split(','); let mime = arr[0].match(/:(.*?);/)[1]; let bstr = atob(arr[1]); let n = bstr.length; let u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime });}// 标准参数var canvas, ctx, configDefault = { width: 200, height: 200};let config = { text: 'avue.top', // 文字 fontFamily: 'microsoft yahei', // 字体 color: '#999', // 颜色 fontSize: 16, // 大小 opacity: 100, // 透明度 bottom: 10, // 下边位置 right: 10, // 右边位置 ratio: 1// 压缩比};/** * 参数 {Object} opt * @param {String} text 水印文本,默认'avue商用通用无敌大水印' * @param {String} font 水印字体,默认'30px 黑体' * @param {Int} canvasWidth 单个水印容器宽度,默认500 * @param {Int} canvasHeight 单个水印容器高度,默认200 * @param {String} textAlign 水印文本对齐方式,默认'center' * @param {String} textStyle 水印文本样式,默认'rgba(100,100,100,0.15)' * @param {Int} degree 水印文本旋转角度,默认 -20 * @param return **/export const watermark = function(opt = {}) { console.log(opt) return new _waterMark(opt);};// 将base64转换为文件export function detailImg(file, option = {}) { return new Promise(function(resolve, reject) { const { text, fontFamily, color, fontSize, opacity, bottom, right, ratio } = option; initParams(); fileToBase64(file, initImg); // 参数初始化 function initParams() { config.text = text || config.text; config.fontFamily = fontFamily || config.fontFamily; config.color = color || config.color; config.fontSize = fontSize || config.fontSize; config.opacity = opacity || config.opacity; config.bottom = bottom || config.bottom; config.right = right || config.right; config.ratio = ratio || config.ratio; } // 加载图片 function initImg(data) { var img = new Image(); img.src = data; img.onload = function() { var width = img.width; var height = img.height; cretedCanvas(width, height); ctx.drawImage(img, 0, 0, width, height); setText(width, height); resolve(dataURLtoFile(document.getElementById('canvas').toDataURL(file.type, config.ratio), file.name)); }; } // 创建画板 function cretedCanvas(width, height) { canvas = document.getElementById('canvas'); if (canvas === null) { canvas = document.createElement('canvas'); canvas.id = 'canvas'; canvas.className = 'avue-canvas'; document.body.appendChild(canvas); } ctx = canvas.getContext('2d'); canvas.width = width; canvas.height = height; } // 添加水印 function setText(width, height) { var txt = config.text; var param = calcParam(txt, width, height); ctx.font = param.fontSize + 'px ' + config.fontFamily; ctx.fillStyle = config.color; ctx.globalAlpha = config.opacity / 100; ctx.fillText(txt, param.x, param.y); } // 计算比例 function calcParam(txt, width, height) { var x, y; // 字体的比例 var calcFontSize = config.fontSize / configDefault.width; var fontSize = calcFontSize * width; if (config.bottom) { y = configDefault.height - config.bottom; } else { y = config.top; } if (config.right) { x = configDefault.width - config.right; } else { x = config.left; } ctx.font = config.fontSize + 'px ' + config.fontFamily; var txtWidth = Number(ctx.measureText(txt).width); x = x - txtWidth; var calcPosX = x / configDefault.width; var calcPosY = y / configDefault.height; x = calcPosX * width; y = calcPosY * height; return { x: x, y: y, fontSize: fontSize }; } // file转base64 function fileToBase64(file, callback) { var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { callback(e.target.result); }; } });}watermark.js
export function randomId () { let chars.length; let id = ''; for (let i = 0; i < 16; i++) { id += chars.charAt(Math.floor(Math.random() * maxPos)); } return id;}class waterMark { constructor(opt = {}) { this.CONTAINERID = randomId(); this.drawCanvas = this.drawCanvas.bind(this); this.parentObserver = this.parentObserver.bind(this); this.Repaint = this.Repaint.bind(this); this.isOberserve = false; this.init(opt); this.drawCanvas(); this.parentObserver(); } init(opt) { this.option = {}; this.option.text = opt.text || 'avue商用通用无敌大水印'; this.option.font = opt.font || '30px 黑体'; this.option.canvasWidth = opt.canvasWidth || 500; this.option.canvasHeight = opt.canvasHeight || 200; this.option.textAlign = opt.textAlign || 'center'; this.option.textStyle = opt.textStyle || 'rgba(100,100,100,0.15)'; this.option.degree = opt.degree || -20; } drawCanvas() { this.isOberserve = true; let divContainer = document.createElement('div'); let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); divContainer.id = this.CONTAINERID; canvas.width = this.option.canvasWidth; canvas.height = this.option.canvasHeight; context.font = this.option.font; context.textAlign = this.option.textAlign; context.fillStyle = this.option.textStyle; context.translate(canvas.width / 2, canvas.height / 2); context.rotate(this.option.degree * Math.PI / 180); context.fillText(this.option.text, 0, 0); let backgroundUrl = canvas.toDataURL('image/png'); this.styleStr = ` position:fixed; top:0; left:0; width:100%; height:100%; z-index:9999; pointer-events:none; background-repeat:repeat; background-image:url('{backgroundUrl}')
; divContainer.setAttribute('style', this.styleStr); document.body.appendChild(divContainer); this.wmObserver(divContainer); this.isOberserve = false; } wmObserver(divContainer) { let wmConf = { attributes: true, childList: true, characterData: true }; let wmObserver = new MutationObserver((mo) => { if (!this.isOberserve) { let _obj = mo[0].target; _obj.setAttribute('style', this.styleStr); _obj.setAttribute('id', this.CONTAINERID); wmObserver.takeRecords(); } }); wmObserver.observe(divContainer, wmConf); } parentObserver() { let bodyObserver = new MutationObserver(() => { if (!this.isOberserve) { let __wm = document.querySelector(#{this.CONTAINERID}`); if (!__wm) { this.drawCanvas(); } else if (__wm.getAttribute('style') !== this.styleStr) { __wm.setAttribute('style', this.styleStr); } } }); bodyObserver.observe(document.querySelector(`#{this.CONTAINERID}).parentNode, { childList: true }); } Repaint(opt = {}) { this.remove(); this.init(opt); this.drawCanvas(); } remove() { this.isOberserve = true; let _wm = document.querySelector(#${this.CONTAINERID}`); _wm.parentNode.removeChild(_wm); }}export default waterMark;
2 .home.vue里使用组件
<template> <div> <div style="width: 400px; position: absolute; top: 200px"> <el-button @click.stop="submit" type="primary">全局水印</el-button> <el-button @click.stop="del" type="danger">删除水印</el-button> </div> </div></template><script>import { watermark } from "../utils/canvas/index.js"; // 引入index.js 水印的配置文件export default { name: "home", data() { return { obj: "", create: false, }; }, methods: { submit() { if(this.create){ this.$message.success('已经创建水印了') return } this.create=true; this.$message.success('添加水印成功')
// 可自定义 宽、高、文本、 字体、颜色、对齐方式、旋转角度等 具体可查index.js配置文件
this.obj=watermark({text:'全局水印演示',}) }, del(){ this.obj.remove(); this.create=false; }, },};</script><style scoped></style>
3 .演示效果