canvas实现水印效果

一、使用canvas创建一个与窗口大小一致的画布,然后使用canvas的fillText的方法绘制水印。

此方法有几个注意点:

1. 画布不能覆盖网页上的有效事件,因些需要给canvas设置pointer-events: none;样式

2.创建的画布大小需要是窗口对角线尺寸的正方形,保证在画布在旋转某个角度时4个角不会出现空白区。同时需要将canvas的与当前窗口的尺寸进行计算出向左、向上的偏移量。

3. 计算绘制的文字长度时,一定要设置font属性,否则会使用画布默认的字体大小计算长度,容易出现bug。

4. 计算行数、列数时,需要注意,尤其在fillText时规划好x,y坐标

5. 在旋转画布时,一定要将旋转中心设置到画布的x,y轴的中心位置,旋转完毕后再复原置原来位置。

import React, { useEffect, useRef } from "react"
import PropTypes from 'prop-types'

export default function Watermark({ text, rotate }) {
    const canvasRef = useRef(null)
    const setCanvasData = () => {
        const canvas = canvasRef.current
        const canvasParent = document.body
        // 画布大小需要为容器的对角线长度,
        // 画布在旋转时不会出现对角空白无水印!!!
        const maxSizeContainer = Math.max(canvasParent.offsetWidth, canvasParent.offsetHeight)
        const minSizeCanvas = Math.ceil(Math.SQRT2 * maxSizeContainer)

        // 设置画面的最小尺寸
        canvas.setAttribute('width', String(minSizeCanvas))
        canvas.setAttribute('height', String(minSizeCanvas))

        // 修改画布在容器中的偏移,使其中心位置与容器的中心位置永远保持一致
        // 在旋转角度时也要以其中心点为中心进行旋转
        canvas.style.position = 'fixed'
        canvas.style.top = - Math.ceil((minSizeCanvas - maxSizeContainer) / 2) + 'px'
        canvas.style.left = - Math.ceil((minSizeCanvas - maxSizeContainer) / 2) + 'px'

        // 画笔
        const ctx = canvas.getContext('2d')

        // 设置笔触样式,font的样式一定要在measureText方法调用前
        ctx.font = '16px 微软雅黑'
        ctx.fillStyle = '#ddd'
        ctx.textAlign = 'left'
        ctx.textBaseline = 'middle'

        // 计算字符串的横向与纵向间距,设置了font的大小与字体
        const offsetX  = Math.ceil(ctx.measureText(text).width) + 60
        const offsetY = 110

        // 列/行数
        const rowCount = Math.ceil(minSizeCanvas / offsetY)
        const colCount = Math.ceil(minSizeCanvas / offsetX)

        // 旋转
        ctx.translate(minSizeCanvas / 2, minSizeCanvas / 2)
        ctx.rotate(rotate * Math.PI / 180)
        ctx.translate(-minSizeCanvas / 2, -minSizeCanvas / 2)

        // 行
        for(let i=0; i<rowCount; i++) {
            // 列
            for(let j=0; j<colCount; j++) {
                ctx.fillText(text, offsetX * j, offsetY * i)
            }
        }
    }

    useEffect(() => {
        window.addEventListener('resize', setCanvasData)
        return function cleanup() {
            window.removeEventListener('resize', setCanvasData)
        }
    }, [])

    useEffect(() => {
        setCanvasData()
    }, [text, rotate])

    return (
        <canvas ref={canvasRef} />
    )
}

Watermark.propTypes = {
    text: PropTypes.string.isRequired,
    rotate: PropTypes.number
}

二、使用canvas的toDataURL方法导出图片的base64的代码,使用css background-repeat属性将图片作为背景进行填充。

import React from "react"
import styles from './scss/wm.module.scss'

const createImage = function (text) {
    const canvas = document.createElement('canvas')
    // 画笔
    const ctx = canvas.getContext('2d')

    // 修改画布在容器中的偏移,使其中心位置与容器的中心位置永远保持一致
    // 在旋转角度时也要以其中心点为中心进行旋转
    canvas.style.display = 'none'

    // 设置笔触样式,font的样式一定要在measureText方法调用前
    ctx.font = '16px 微软雅黑'
    ctx.fillStyle = '#ddd'
    ctx.textAlign = 'left'
    ctx.textBaseline = 'middle'

    // 计算字符串的横向与纵向间距,设置了font的大小与字体
    const offsetX  = Math.ceil(ctx.measureText(text).width) + 60
    // 设置画面的最小尺寸
    canvas.setAttribute('width', String(offsetX))
    // 高度可以增加行间距
    canvas.setAttribute('height', String(100))

    ctx.fillText(text, 0, 8)

    return canvas.toDataURL('image/png')
}

function WaterMark({ text, rotate }) {
    const [count, setCount] = React.useState(0)

    const onResize = React.useCallback(() => {
        // 设置画布大小
        const canvasParent = document.body
        // 画布大小需要为容器的对角线长度,
        // 画布在旋转时不会出现对角空白无水印!!!
        const maxSizeContainer = Math.max(canvasParent.offsetWidth, canvasParent.offsetHeight)
        const minSizeCanvas = Math.ceil(Math.SQRT2 * maxSizeContainer)
        setCount(minSizeCanvas)
    }, [])

    React.useEffect(() => {
        onResize()
        window.addEventListener('resize', onResize)
        return () => {
            window.removeEventListener('resize', onResize)
        }
    }, [])

    return (
        <div className={styles.container} style={{
            backgroundImage: `url(${createImage(text)})`,
            height: count,
            width: count
        }} />
    )
}

export default WaterMark
.container {
  transform: rotate(-30deg) translate(-20%, -40%);
  background-repeat: repeat;
  width: 200%;
  min-width: 200%;
  height: 200%;
  min-height: 200%;
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Canvas 全屏水印通常是指在 HTML5 的 `<canvas>` 元素上添加一个透明度较低的图像或文字,使其在整个页面背景中显示出来,即使canvas内容被放大或缩小时,水印也会保持始终可见。这样做的目的是为了保护版权或者提供品牌标识。 实现canvas全屏水印的方法主要包括以下几个步骤: 1. 创建 canvas 元素:首先在 HTML 中创建一个 `<canvas>` 标签,并设置其宽度和高度与浏览器视窗相同,使用 `requestAnimationFrame` 或 `window.onload` 来确保 canvas 加载完成。 ```html <canvas id="watermark-canvas"></canvas> ``` 2. 绘制水印:在 JavaScript 中,获取 canvas 的上下文 (`context`),然后在每一帧(动画循环)里绘制水印。你可以选择一个半透明的背景色(如 rgba(0,0,0,0.5))作为水印,然后在其上绘制文本或图片。 ```javascript const canvas = document.getElementById('watermark-canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; function drawWatermark() { ctx.fillStyle = 'rgba(0,0,0,0.5)'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制文字水印 const text = 'Your Watermark Text'; ctx.font = '16px Arial'; ctx.fillStyle = 'white'; ctx.fillText(text, 10, canvas.height - 20); } // 添加到动画循环 requestAnimationFrame(drawWatermark); ``` 3. 动态调整:如果你希望水印跟随窗口大小变化,你需要在 `drawWatermark` 函数中更新 canvas 的尺寸。 4. 隐藏canvas本身:为了完全实现全屏效果,可以设置 `canvas` 的 `display` 属性为 `none`,使实际的画布内容不显示,只留下水印。 ```javascript canvas.style.display = 'none'; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值