js结合canvas制作水印添加器小工具 原创 精华

中软国际AIoT开发者社区
发布于 2022-6-6 10:02
浏览
4收藏

作者:钱林川

前言

随着搬运工的逐渐增加,原创作者的利益收到了极大的影响.所以给图片或视频加上水印显得极其重要,他可以有效的维护原创作者的版权防止盗版.本文分享一个由canvas和vue.js制作的图片水印添加器.

效果展示

js结合canvas制作水印添加器小工具-鸿蒙开发者社区

实现功能

自定义水印的文字及颜色,水印的位置,旋转角度,大小,透明度,是否重复显示,以及选择为重复时可以选择文字之间的水平间距和垂直间距,在设置为合适的图片时点击下载按钮即可下载得到完成图.如果觉得效果不好也可以点击重置按钮瞬间清屏.同时还支持logo图水印.

实现思路

  1. 首先要引入vue.js以及elementui组件和样式如下:

    <!-- 引入样式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"/>
    <!-- 引入 Vue -->
    <script src="https://unpkg.com/vue@next"></script>
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/element-plus"></script>
    
  2. html代码如下:

    <div id="app">
        <div class="home">
            <div class="mycontainer">
                <canvas id="canvasImg" @click="uploadfile()"></canvas>
                <div class="selectbox box" v-show="imgnode">
                    <div style="max-width:330px">
                        <input type="text" class="canvastext" @input="addtext" v-model="inputval" placeholder="请输入水印文字"/>
                        水印颜色:<input type="color" style="margin-right:20px" class="colorselect" placeholder="" v-model="color" @change="loop">
                        取色器:<input type="color" class="colorselect">
                        <ul class="btns">
                            <li class="smallprant"><button @click="addlogo">上传水印或logo图</button></li>
                            <li><button @click="unset">重新设置水印</button></li>
                        </ul>
                    </div>
                    <div class="box">
                        <ul class="centerselect">
                            <li>位置&nbsp;&nbsp;
                                <el-select v-model="position" placeholder="请选择" @change="loop">
                                    <el-option label="中心" value="中心"></el-option>
                                    <el-option label="左上" value="左上"></el-option>
                                    <el-option label="上" value="上"></el-option>
                                    <el-option label="右上" value="右上"></el-option>
                                    <el-option label="右" value="右"></el-option>
                                    <el-option label="右下" value="右下"></el-option>
                                    <el-option label="下" value="下"></el-option>
                                    <el-option label="左下" value="左下"></el-option>
                                    <el-option label="左" value="左"></el-option>
                                </el-select>
                            </li>
                            <li class="rotate">旋转&nbsp;&nbsp;
                                <el-select v-model="rotate" placeholder="请选择" @change="loop">
                                    <el-option label="0°" :value="0"></el-option>
                                    <el-option label="15°" :value="15"></el-option>
                                    <el-option label="30°" :value="30"></el-option>
                                    <el-option label="45°" :value="45"></el-option>
                                    <el-option label="60°" :value="60"></el-option>
                                </el-select>
                            </li>
                            <li>重复&nbsp;&nbsp;
                                <el-select v-model="repetition" placeholder="请选择" @change="loop">
                                    <el-option label="不重复" :value="false"></el-option>
                                    <el-option label="重复" :value="true"></el-option>
                                </el-select>
                            </li>
                        </ul>
                    </div>
                    <div class="box">
                        <span>x间距</span>
                        <div class="block" style="margin:10px 0 0 0;">
                            <el-slider v-model="value0" :step="1" :max="slidermax" @input="loop"></el-slider>
                        </div>
                        <span>y间距</span>
                        <div class="block" style="margin:10px 0 0 0;">
                            <el-slider v-model="value1" :step="1" :max="slidermax" @input="loop"></el-slider>
                        </div>
                        <span>大小</span>
                        <div class="block" style="margin:10px 0;">
                            <el-slider v-model="value2" :step="1" :max="slidermax" @input="loop"></el-slider>
                        </div>
                        <span>透明度</span>
                        <div class="block" style="margin:10px 0;">
                            <el-slider v-model="value3" :step="0.1" :max='1' @input="loop"></el-slider>
                        </div>
                    </div>
                </div>
                <el-button v-show="imgnode" style="margin-top:10px;" @click="saveimg">保存图片到本地</el-button>
            </div>
        </div>
    </div>
    
  3. 点击按钮后需要选择上传水印的图片方法如下:

    整体思路如下:

    loop () {
       this.clear()//1.清空画布
       if(this.imgnode)this.drawimg(this.imgnode)//2.判断是否上传了图片,有就绘制图片
       if(this.inputval)this.drawtext(this.inputval)//3.判断输入框是否有文字,有绘制文字
       if(this.logo)this.drawlogo(this.logo)//4.判断是否添加logo图片,有就绘制logo
        },
            
    

    下面先介绍一下项目中运行到的一些函数方法:

    3.1 绘制背景函数,先拿到页面中cavans元素,运用drawImage()画出背景

    //绘制图片
    drawimg(url){
       let canvas = document.getElementById('canvasImg')
       let context = canvas.getContext('2d')
       context.drawImage(url, 0, 0)
          },
    

    3.2 绘制字体水印,同理先拿到canvas元素, 运用到的方法:

    context.font:设置字体的大小 ,

    context.fillStyle:设置字体的类型颜色,

    repetition:判断是否重复 ,

    globalAlpha:设置字体的透明度,

    rotate:旋转角度,

    translate:偏移位置,

    setposition()函数:设置水印的位置,主要用到了canvas.width和canvas.height,

    中心点位置: strarr = [canvas.width / 2, canvas.height / 2],

    左上角位置: strarr = [0, 0];

    通过改变x,y将元素放置在画布各个位置,绘制logo水印同理。

    //绘制字体水印
    drawtext(value){
        let canvas = document.getElementById('canvasImg') //获取cavans
        let context = canvas.getContext('2d')
        let strarr = this.setposition()
        context.font = this.value2+"px '宋体'"
        context.fillStyle = this.color
       if (!this.repetition) { //是否想要文字重复,默认不重复
            context.save()
            context.globalAlpha = this.value3
            context.translate(strarr[0], strarr[1])
            context.rotate((Math.PI/180)*(this.rotate*1))
            context.translate(-strarr[0], -strarr[1])
            context.fillText(value, strarr[0], strarr[1]+this.value2)
            context.restore()
              } else {
       for (let i=0 ; i < canvas.width ; i += (this.value2*this.inputval.length +this.value0)) {
          for (let j = 0 ; j < canvas.height ; j += (this.value2 + this.value1)) {
              context.save()
              context.globalAlpha = this.value3
              context.translate(strarr[0]+i, strarr[1]+j)
              context.rotate((Math.PI/180)*(this.rotate*1))
              context.translate(-strarr[0]-i, -strarr[1]-j)
              context.fillText(value, (strarr[0])+i, (strarr[1])+j+this.value2)
              context.restore()
                                }
                            }
                        }
                    },
    

    3.3 清屏函数:如果在绘制过程中,对绘制的效果不满意,想要重新绘制,就涉及到清屏操作,这里我是将输入的文字(inputval)和选中的水印(logo)设置为空再重新绘制, 代码如下

    //重新设置
    unset(){
        //输入的文字
        this.inputval = null
        //选中的水印
        this.logo = null
        this.loop()
                   },
    

    3.4 保存图片代码:绘制完成后就是保存图片代码,这里我是先创建了一个url元素用来存放下载的位置,文件名用new Date().getTime()+‘.png’ 这种形式来避免文件名重复,当我们下载完成之后创建的url并没有被释放,此时就需要使用 URL.revokeObjectURL()方法将内存释放掉,此处做了一个延迟,让url内存5秒后被释放。

    //保存图片到本地
    saveimg () {
       let canvas = document.getElementById('canvasImg')
       canvas.toBlob(blob => {
       let url = URL.createObjectURL(blob)
       let save_link = document.createElement('a');
       save_link.href = url;
       save_link.download = new Date().getTime()+'.png';
       let event = document.createEvent('MouseEvents');
       event.initEvent("click", true, false);
       save_link.dispatchEvent(event);
       setTimeout(() => {
          URL.revokeObjectURL(url)
                 }, 5000);
               })
           },
    

    3.5 功能函数:使用这种方法创建元素可以节约资源避免浪费

    //----功能函数----
       loadImg (url) {
       const img = document.createElement('img')
       img.src = url
       return img
    },
    
  4. css代码如下:

    		*{
                margin: 0;
                padding: 0;
            }
            .title{
                font-size: 20px;
                margin: 30px;
                color:#888;
            }
            canvas{
                background-color: #ccc;
                max-width: 960px;
            }
            .cavansimg{
                width: 230px;
                height: 50px;
                background-color: #409EFF;
                border-radius: 5px;
                cursor: pointer;
            }
            .mycontainer {
                width: 960px;
                text-align: center;
                margin:0 auto;
                padding-bottom: 20px;
            }
            .textstyle{
                width: 100%;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .selectbox {
                display: flex;
                margin-top: 20px;
                justify-content: space-between;
            }
            .box{
                width: 100%;
                display: flex;
                justify-content: space-between;
                align-items: center;
                flex:1;
                color: #409EFF;
            }
            li {
                list-style: none;
            }
            .btns {
                display: flex;
                justify-content: space-between;
                margin-left: 20px;
            }
            .btns button {
                width: 120px;
                height: 50px;
                margin-right: 30px;
                border-radius: 10px;
                background-color: #409EFF;
                color: #fff;
                outline: none;
                border: none;
            }
            .colorselect {
                border-radius: 5px;
                width: 80px;
                height: 40px;
                outline: none;
                border: none;
            }
            .canvastext {
                height: 40px;
                width: 150px;
                border-radius: 5px;
                text-indent: 10px;
                border:1px solid #409EFF;
                border: none;
                outline: none;
            }
            .centerselect{
                margin:20 0;
                display: flex;
                justify-content: space-between;
                color: #409EFF;
            }
            .centerselect li {
                height: 50px;
                line-height: 50px;
            }
            span {
                display: inline-block;
            }
            .smallprant {
                position: relative;
            }
            html,body {user-select: none;}
            .block {
                width: 150px;
            }
    

初始界面:
js结合canvas制作水印添加器小工具-鸿蒙开发者社区

点击按钮选择图片后:

js结合canvas制作水印添加器小工具-鸿蒙开发者社区

源码地址

https://gitee.com/touxing123/watermark-adder.git

总结

以上就是水印制作工具的全部过程了,最终效果跟上面一样,主要就是运用了canvas的一些属性,欢迎各位开发者一起研究讨论,希望本次分享对大家有所帮助.

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
4
收藏 4
回复
举报
5条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

水印对原创的保护确实重要。

回复
2022-6-6 11:35:12
wx629d7b5d697d5
wx629d7b5d697d5

学到了,钱老师还是很厉害的

回复
2022-6-6 12:00:24
物联风景
物联风景

这个好,感谢分享

回复
2022-6-6 13:51:23
wx62b086ec3413c
wx62b086ec3413c

钱老师,代码仓打不开,帮忙看下,谢谢!

回复
2022-6-20 22:52:23
中软国际AIoT开发者社区
中软国际AIoT开发者社区 回复了 wx62b086ec3413c
钱老师,代码仓打不开,帮忙看下,谢谢!

git仓库问题,已经申请开源了,估计要等1-2天

回复
2022-6-21 10:41:25
回复
    相关推荐