微信小程序图片水印文字(含旋转交错)功能

功能需求

        微信小程序实现图片水印功能,有6种位置模式:左上角左下角中间右上角右下角平铺,并且平铺时支持旋转和文字交错。

最终实现效果

微信扫码查看或者搜索小程序:工具迷你仓https://i.postimg.cc/7Z2VB04L/qrcode.jpg

逻辑设计(分两部分)

        第一部分是单个文字的水印(即左上角、左下角、中间、右上角、右下角位置),通过计算图片宽高和文字宽高计算出绘画水印的位置坐标。

        第二部分是平铺水印,先生成透明水印图,再将水印图放在目标图上。

关键代码

一、左上角、左下角、中间、右上角、右下角水印

        1、在canvas上画一张图片,canvas的宽高等于图片的宽高

        2、通过计算图片的宽高以及文字的宽高(measureText方法),可计算出左上角、左下角、中间、右上角、右下角的位置坐标:

        左上角=(0, 0)

        左下角=(0, 图片的高度-文字的高度)

        中间=(图片的宽度/2-文字的宽度/2, 图片的高度/2-文字的高度)

        右上角=(图片的宽度-文字的宽度, 0)

        右下角=(图片的宽度-文字的宽度, 图片的高度-文字的高度)  

左上角水印
左下角水印
中间水印
右上角水印
右下角水印
let textMetrics = ctx.measureText(maskText);
//水印文字宽度
let { width: textWidth, actualBoundingBoxAscent, actualBoundingBoxDescent } = textMetrics;
//水印文字高度
let textHeight = actualBoundingBoxAscent ? (actualBoundingBoxAscent + actualBoundingBoxDescent) : (textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent);

// 设置canvas宽高
canvas.width = imgWidth
canvas.height = imgHeight

// 创建目标图片对象
const image = canvas.createImage();
image.src = imgFilePath;
image.onload = () => {

    // 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // 将图片绘制到canvas上
    ctx.drawImage(image, 0, 0, canvas.width, canvas.height)

    let posXmargin = this.data.posXmargin // 自定义离左/右边的距离
    let posYmargin = this.data.posYmargin // 自定义离上/下边的距离
    switch (pos) {
        case 'left top': //左上角
            let lt_x = posXmargin
            let lt_y = posYmargin + textHeight
            ctx.font = font
            ctx.fillStyle = fontColor
            ctx.fillText(maskText, lt_x, lt_y)
            ctx.restore()
            ctx.save()
            break;
        case 'left bottom': //左下角
            let lb_x = posXmargin
            let lb_y = imgHeight - posYmargin
            ctx.font = font
            ctx.fillStyle = fontColor
            ctx.fillText(maskText, lb_x, lb_y)
            ctx.restore()
            ctx.save()
            break;
        case 'center': //居中
            ctx.translate(imgWidth / 2, imgHeight / 2)// 移动画布到中心位置,以便围绕中心点旋转图片
            ctx.rotate(angle * Math.PI / 180)// 旋转图片
            ctx.translate(-textWidth / 2, textHeight / 2)// 再次移动画布回到文字开始位置
            ctx.font = font
            ctx.fillStyle = fontColor
            ctx.fillText(maskText, 0, 0)
            ctx.restore()
            ctx.save()
            break;
        case 'right top': //右上角
            let rt_x = imgWidth - textWidth - posXmargin
            let rt_y = posYmargin + textHeight
            ctx.font = font
            ctx.fillStyle = fontColor
            ctx.fillText(maskText, rt_x, rt_y)
            ctx.restore()
            ctx.save()
            break;
        case 'right bottom': //右下角
            let rb_x = imgWidth - textWidth - posXmargin
            let rb_y = imgHeight - posYmargin
            ctx.font = font
            ctx.fillStyle = fontColor
            ctx.fillText(maskText, rb_x, rb_y)
            ctx.restore()
            ctx.save()
            break;
    }

    ctx.restore()

    // 将canvas转为图片
    wx.canvasToTempFilePath({
        canvas: canvas,
        success: (r) => {
            wx.hideLoading()
            this.setData({ wmImgFilePath: r.tempFilePath })
        },
    })
}

二、平铺水印

        1、文字平铺

                用2个for循环嵌套(画布X轴嵌Y轴),文平文字间隔和垂直文字间隔分别为:x_interval、y_interval

平铺
平铺水印
for (let x = 0; x < canvas.width; x += x_interval) {
    for (let y = 0; y < canvas.height; y += y_interval) {
        ctx.translate(x, y)
        ctx.font = font
        ctx.fillStyle = fontColor
        ctx.fillText(maskText, 0, 0);
        ctx.restore()
        ctx.save()
    }
}

        2、文字交错

                偶数行的文字整体往右移:半个文字宽度

文字交错
let cross_intereval = textWidth / 2
let cross = this.data.cross // 隔行标志位
for (let x = 0; x < canvas.width; x += x_interval) {
    let cross_flag = false
    for (let y = 0; y < canvas.height; y += y_interval) {
        let _x = cross_flag ? x + cross_intereval : x
        cross && (cross_flag = !cross_flag)
        ctx.translate(_x, y)
        ctx.font = font
        ctx.fillStyle = fontColor
        ctx.fillText(maskText, 0, 0);
        ctx.restore()
        ctx.save()
    }
}

        3、水印旋转

                (1) 生成一张正方形透明水印图,水印图的宽高=目标图的对角线长度。

                (2)将水印图铺在目标图上面,并加上旋转即可

文字交错+旋转
// 第一步:生成 “边长=图片对角线长度” 的水印图
const borderWidth = Math.ceil(Math.sqrt(imgWidth * imgWidth + imgHeight * imgHeight)
)
// 设置canvas宽高
canvas.width = borderWidth
canvas.height = borderWidth

let wm_interval = this.data.interval
let y_interval = textHeight + wm_interval
let x_interval = textWidth + wm_interval
let cross_intereval = textWidth / 2
let cross = this.data.cross // 隔行标志位
for (let x = 0; x < canvas.width; x += x_interval) {
    let cross_flag = false
    for (let y = 0; y < canvas.height; y += y_interval) {
        let _x = cross_flag ? x + cross_intereval : x
        cross && (cross_flag = !cross_flag)
        ctx.translate(_x, y)
        ctx.font = font
        ctx.fillStyle = fontColor
        ctx.fillText(maskText, 0, 0);
        ctx.restore()
        ctx.save()
    }
}
// 将canvas转为水印图片
wx.canvasToTempFilePath({
    canvas: canvas,
    success: (res) => {
        // 临时水印图片
        const tempWmImgPath = res.tempFilePath

        // 第二步:创建目标图片对象
        const image = canvas.createImage();
        image.src = imgFilePath;
        image.onload = () => {

            canvas.width = imgWidth
            canvas.height = imgHeight

            // 清除画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // 将图片绘制到canvas上
            ctx.drawImage(image, 0, 0, imgWidth, imgHeight)

            // 第三步:将水印绘制到canvas上
            const wmImage = canvas.createImage();
            wmImage.src = tempWmImgPath;
            wmImage.onload = () => {

                // 保存当前环境的状态:这样可以在旋转后恢复到之前的状态
                ctx.save();
                // 移动画布到中心位置,以便围绕中心点旋转图片
                ctx.translate(imgWidth / 2, imgHeight / 2);
                // 旋转图片(以弧度计)
                ctx.rotate(angle / 180 * Math.PI); // 45度 = Math.PI / 4 弧度
                // 再次移动画布回到原始位置,以便图片绘制在正确的位置(考虑到旋转)
                ctx.translate(-wmImage.width / 2, -wmImage.height / 2);
                // 绘制图片
                ctx.drawImage(wmImage, 0, 0);

                // 恢复之前保存的画布状态(如果不调用,之后的绘制将会受到影响)
                ctx.restore();

                // 最后:将canvas转为图片,图+印
                wx.canvasToTempFilePath({
                    canvas: canvas,
                    success: (r) => {
                        wx.hideLoading()
                        this.setData({ wmImgFilePath: r.tempFilePath })
                    },
                })
            }
        }
    },
})

总结

        本人踩的坑,平铺水印时直接旋转文字,结果当文字长度或者旋转角度不同时,文字会重叠,计算了两天三角函数sin和cos。。。

        踩坑原因:在需求分析阶段对功能的剖析不够,没认真分析平铺水印的规律,对市场现有的功能使用不足。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值