JS前端基于canvas给图片添加水印


Posted in Javascript onNovember 11, 2020

前两天给个人网站添加了一个小功能,就是在文章编辑上传图片的时候自动给图片加上水印。给网页图片添加水印是个常见的功能,也是互联网内容作者保护自己版权的方法之一。本文简单记录一下借助canvas在前端实现图片添加水印的实现方法。
canvas元素其实就是一个画布,我们可以很方便地绘制一些文字、线条、图形等,它也可以将一个img标签里渲染的图片画在画布上。

在上传文件到后端的时候,使用input标签读取用户本地文件后得到的其实是一个Blob对象(更精确的说是File对象,特殊的Blob对象);而在页面上展示一个图片使用的是img标签;绘制功能用canvas实现。添加水印的功能需要在img标签、canvas画布、Blob对象这三者之间相互转换,通过一些API可以完成这个工作:

JS前端基于canvas给图片添加水印

我们可以从本地读取图片Blob,然后渲染到img标签,使用canvas绘制img内容并且绘制水印内容到画布,再将canvas内容转为Blob对象上传服务器,这样就完整实现了图片+水印的功能。

一、本地读取图像文件渲染到img标签

本地读取图片文件将会得到一个Blob对象,我们可以借助FileReader.readAsDataURL方法读取Blob的内容,并得到一个Base64编码的文件内容,可以将该内容赋值给img.src从而在浏览器上渲染出本地的图像。当然,img并非必须渲染到DOM树。读取操作是个异步操作,读取完成会触发load事件,为了便于之后的调用,我们可以用一个Promise包装这个操作,最后返回一个Promise对象。

function blobToImg (blob) {
 return new Promise((resolve, reject) => {
  let reader = new FileReader()
  reader.addEventListener('load', () => {
   let img = new Image()
   img.src = reader.result
   img.addEventListener('load', () => resolve(img))
  })
  reader.readAsDataURL(blob)
 })
}

二、将img标签内容绘制到canvas画布

调用canvas元素画布上下文对象的drawImage方法即可实现将img内容绘制到画布。

function imgToCanvas (img) {
 let canvas = document.createElement('canvas')
 canvas.width = img.width
 canvas.height = img.height
 let ctx = canvas.getContext('2d')
 ctx.drawImage(img, 0, 0)
 return canvas
}

drawImage这个方法可以传入多个参数,以定义绘制的图像的范围,这里传入的0, 0定义从图像左上角开始绘制,后面可以继续传入两个参数来定义图像的绘制终点,不过这里整个图片都要绘制到canvas,所以采用默认值即可。

三、canvas画布上绘制水印并转换为Blob对象

在图片上传的时候,我们通常采用FormData,图片文件以一个Blob对象的形式放到FormData中,所以我们需要把canvas再转为Blob以便文件上传等操作。利用HTMLCanvasElement.toBlob方法:

function watermark (canvas, text) {
 return new Promise((resolve, reject) => {
  let ctx = canvas.getContext('2d')
  // 设置填充字号和字体,样式
  ctx.font = "24px 宋体"
  ctx.fillStyle = "#FFC82C"
  // 设置右对齐
  ctx.textAlign = 'right'
  // 在指定位置绘制文字,这里指定距离右下角20坐标的地方
  ctx.fillText(text, canvas.width - 20, canvas.height - 20)
  canvas.toBlob(blob => resolve(blob))
 })
}

四、图片添加水印完整接口

将以上三个步骤结合起来,就完整地实现了从图片添加水印,下面是一个简单的使用示例:从本地选择一个图片文件,然后添加水印后,在传入的dom元素下预览添加水印后的图片。

function imgWatermark (dom, text) {
 let input = document.createElement('input')
 input.setAttribute('type', 'file')
 input.setAttribute('accept', 'image/*')
 input.onchange = async () => {
  let img = await blobToImg(input.files[0])
  let canvas = imgToCanvas(img)
  let blob = await watermark(canvas, text)
  // 此处将Blob读取到img标签,并在dom内渲染出来;如果是上传文件,可以将blob添加到FormData中
  let newImage = await blobToImg(blob)
  dom.appendChild(newImage)
 }
 input.click()
}

给页面加一个id为container的div元素,然后如下调用:

let dom = document.querySelector('#container')
imgWatermark(dom, '水印文字')

这样就完整地给图片添加了水印效果,下面看一下实际效果,你也可以在线体验。

添加水印前:

JS前端基于canvas给图片添加水印

添加水印后(水印内容:“腾冲·清凉山”):

JS前端基于canvas给图片添加水印

五、总结

本文仅仅介绍了图像+水印文字的简单实现,但是涉及的一些接口其实很有用。比如有时候遇到的一个功能是头像上传的预览和剪裁,这时候你可以利用FileReader来读取文件内容预览,利用CanvasRenderingContext2D.drawImage来实现剪裁功能。关于本文涉及接口的更多详细用法,可以参照MDN文档,文章中的API都使用了链接的形式链接到了MDN。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
IE和Firefox在JavaScript应用中的兼容性探讨
Apr 01 Javascript
JQuery 浮动导航栏实现代码
Aug 27 Javascript
js ondocumentready onmouseover onclick onmouseout 样式
Jul 22 Javascript
使用 JScript 创建 .exe 或 .dll 文件的方法
Jul 13 Javascript
背景图跟随鼠标移动的Mootools插件实现代码
Dec 12 Javascript
ASP.NET jQuery 实例6 (实现CheckBoxList成员全选或全取消)
Jan 13 Javascript
jquery不会自动回收xmlHttpRequest对象 导致了内存溢出
Jun 18 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
Nov 17 Javascript
vuejs指令详解
Feb 07 Javascript
浅谈angularjs依赖服务注入写法的注意点
Apr 24 Javascript
jQuery实现动态添加、删除按钮及input输入框的方法
Apr 27 jQuery
vue.js 获取select中的value实例
Mar 01 Javascript
vant-ui框架的一个bug(解决切换后onload不触发)
Nov 11 #Javascript
使用Vant完成Dialog弹框案例
Nov 11 #Javascript
vue实现lodop打印功能的示例
Nov 11 #Javascript
解决vant的Toast组件时提示not defined的问题
Nov 11 #Javascript
vue mvvm数据响应实现
Nov 11 #Javascript
Js数组扁平化实现方法代码总汇
Nov 11 #Javascript
使用Vant完成通知栏Notify的提示操作
Nov 11 #Javascript
You might like
也谈截取首页新闻 - 范例
2006/10/09 PHP
PHP静态新闻列表自动生成代码
2007/06/14 PHP
PHP XML数据解析代码
2010/05/26 PHP
php按百分比生成缩略图的代码分享
2014/05/10 PHP
PHP获取数组最大值下标的方法
2015/05/12 PHP
wampserver改变默认网站目录的办法
2015/08/05 PHP
PHP crypt()函数的用法讲解
2019/02/15 PHP
基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作
2020/08/17 PHP
不同Jquery版本引发的问题解决
2013/10/14 Javascript
jquery简单实现滚动条下拉DIV固定在头部不动
2013/11/25 Javascript
jQuery+html5实现div弹出层并遮罩背景
2015/04/15 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
JavaScript满天星导航栏实现方法
2018/03/08 Javascript
详解extract-text-webpack-plugin 的使用及安装
2018/06/12 Javascript
vue开发环境配置跨域的方法步骤
2019/01/16 Javascript
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
js实现开关灯效果
2020/03/30 Javascript
vue解决使用$http获取数据时报错的问题
2019/10/30 Javascript
vue移动端使用canvas签名的实现
2020/01/15 Javascript
vue中的循环对象属性和属性值用法
2020/09/04 Javascript
vue.js+element 默认提示中英文操作
2020/11/11 Javascript
[01:01:13]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第三场
2018/04/06 DOTA
[06:53]2018DOTA2国际邀请赛寻真——勇于创新的Vici Gaming
2018/08/14 DOTA
PyQt5实现简易电子词典
2019/06/25 Python
python将字典列表导出为Excel文件的方法
2019/09/02 Python
Python使用Socket实现简单聊天程序
2020/02/28 Python
Django Admin 上传文件到七牛云的示例代码
2020/06/20 Python
python实现ping命令小程序
2020/12/28 Python
Lulu & Georgia官方网站:购买地毯、家具、抱枕、壁纸、床上用品等
2018/03/19 全球购物
来自世界上最好大学的在线课程:edX
2018/10/16 全球购物
2013英文求职信模板范文
2013/11/15 职场文书
农贸市场管理制度
2014/01/31 职场文书
弘扬焦裕禄精神走群众路线思想汇报
2014/09/12 职场文书
2014年教研组工作总结
2014/11/26 职场文书
2015年青年教师工作总结
2015/05/25 职场文书
MySQL数据库如何查看表占用空间大小
2022/06/10 MySQL