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%;
}

转载于:canvas实现水印效果_老白干的博客-CSDN博客_canvas 水印

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值