利用 canvas / svg 实现水印

个人组件网站:https://luoheix.github.io/watermark

利用 canvas 实现(2020-08-03)

利用 canvas 标签生成图片,作为页面元素的背景图来实现水印效果。

js中的实现

效果

代码

(水印位置自行设置)

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <title>Document</title>
  <style>
  </style>
</head>
<body>
  <script>
    function getCanvasUrl(text, fontSzie, color, width = 500, height = 300) {
      let canvas = document.createElement('canvas');
      let context = canvas.getContext('2d');
      canvas.width = width;
      canvas.height = height;
      context.font = fontSzie + 'px Arial';
      context.fillStyle = color;
      context.textAlign = "center";
      context.textBaseline = "middle";
      context.rotate(Math.PI / 180 * -30); // 旋转
      context.fillText(text, 130, 250); // 填充文本,设置位置
      var base64Url = canvas.toDataURL('image/png'); // 生成url
      return base64Url;
    }

    const text = `${(new Date()).toLocaleDateString()} 用户名用户名`;
    var watermarkDiv = document.createElement('div');
    watermarkDiv.setAttribute('style', `
      position:fixed;
      top:0;
      left:0;
      z-index:9999;
      width:100%;
      height:100%;
      opacity: 0.1;
      pointer-events:none;
      background-repeat:repeat;
      background-image:url('${getCanvasUrl(text, 28, 'rgb(128,128,128)')}')
    `);
    document.body.appendChild(watermarkDiv);
  </script>
</body>
</html>

设置行内样式缺陷

canvas生成路径会很长,直接设置行内样式会在页面上占据很大空间。

react 中利用 style-it

页面效果

html效果

css效果

代码

import React, { useState, useEffect } from 'react';
import Style from 'style-it';

// 生成水印背景图地址
const getCanvasUrl = (text = '用户名用户名', width = 500, height = 300, fontSize = 28, color = 'rgb(128,128,128)') => {
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d');
  canvas.width = width;
  canvas.height = height;
  context.font = fontSize + 'px Arial';
  context.fillStyle = color;
  context.textAlign = "center";
  context.textBaseline = "middle";
  context.rotate(Math.PI / 180 * -30);
  context.fillText(`${(new Date()).toLocaleDateString()} ${text}`, 130, 250);
  return canvas.toDataURL('image/png');
};

const Index = props => {
  const [canvasUrl, setCanvasUrl] = useState('');

  useEffect(() => {
    setCanvasUrl(getCanvasUrl());
  }, []);

  return (
      <Style>
        {`
          .watermark {
            position:fixed;
            top:0;
            left:0;
            z-index:9999;
            width:100%;
            height:100%;
            opacity: 0.1;
            pointer-events:none;
            background-repeat:repeat;
            background-image:url('${canvasUrl}')
          }
        `}
        <div className="watermark"></div>
      </Style>
  );
};
export default Index;

利用 svg 实现“更简单、性能更高”(2020-11-04)

生成 svg 标签,直接作为页面元素的背景图来实现水印效果。

特点:无需生成图片,可直接内嵌在 html 中或直接作为背景图使用。

效果

style

index.jsx

注意:svg 作为图片或浏览器直接打开必须转义,且需定义 xmlns="http://www.w3.org/2000/svg"。如果内嵌到html标签中则不需要。最佳 svg 转义方式

import React, { useState, useEffect } from 'react';

// 因为安全原因 svg 需转译以便作为背景图使用,也可直接在浏览器中打开
// 因为要保留 xvg 可读性,所以使用自定义方法进行转义
const svgToUrl = str => {
  return `data:image/svg+xml,${str
    .replace(/\n/g, '')
    .replace(/<!--(.*)-->/g, '') // 必须去掉注释
    .replace(/[\r\n]/g, ' ') // 最好去掉换行
    .replace(/"/g, "'") // 单引号是保留字符,双引号改成单引号减少编码
    .replace(/%/g, '%25')
    .replace(/&/g, '%26')
    .replace(/#/g, '%23')
    .replace(/{/g, '%7B')
    .replace(/}/g, '%7D')
    .replace(/</g, '%3C')
    .replace(/>/g, '%3E')}`;
};
/**
 * 生成 svg 字符串
 * @param {object} options 参数
 * text 水印文字
 * <text> 属性(x y transform) 方向位置按需调整
 * <svg> 中fill属性决定字体颜色
 */
const getCanvasUrl = options => {
  const {
    text = `${new Date().toLocaleDateString()} Svg生成水印`,
    width = 500,
    height = 300,
    fontSize = 28,
    color = 'rgb(128,128,128)',
    fontFamily = 'inherit',
  } = options || {};
  return `<svg
    width="${width}"
    height="${height}"
    fill="${color}"
    xmlns="http://www.w3.org/2000/svg"
  >
    <text
      x="38%"
      y="77%"
      transform="rotate(-35, 100 100)"
      font-size="${fontSize}"
      font-family="${fontFamily}"
      text-anchor="middle"
      dominant-baseline="middle"
    >${text}</text>
  </svg>`;
};

const WatermarkSvg = () => {
  const [svgUrl, setSvgUrl] = useState('');

  useEffect(() => {
    const newSvgUrl = svgToUrl(getCanvasUrl());
    setSvgUrl(newSvgUrl);
  }, []);

  return (
    <div
      style={{
        position: 'fixed',
        top: 0,
        left: 0,
        zIndex: 9999,
        width: '100%',
        height: '100%',
        opacity: 0.2,
        pointerEvents: 'none',
        background: `url("${svgUrl}") repeat`,
      }}
    />
  );
};
export default WatermarkSvg;

参考资料

style-it 地址

前端水印生成方案

h5页面利用js添加水印

如何让文字作为CSS背景图片显示? «  张鑫旭-鑫空间-鑫生活

svg 标签的 xmlns 属性 · 黑熊君 · 语雀

小程序 - 添加水印页面 · 黑熊君 · 语雀