一、需求场景
1、前端动态二维码组合
2、水印技术
有的网站信息内容专利、防窃取的要求,为了让用户下载分享的内容不被随意对外分享,则需要将用户下载的图片上盖上一层署名信息,从而防止有人下载图片后冒充作者,侵犯作者权益。
3、还有很多场景...
二、解决方案
解决方案的前提是利用客户端的能力,纯前端来解决。作为前端开发者,对于画图来说,Canvas能力是完全足够的,2D的、3D的都是可以完成,我这里的解决方案就是利用Canvas来做的。首先要利用canvas画图能力,前提两张图要合并的相对的位置,大小需要先知道,这需要你先跟视觉同学沟通好,实际涉及到的Canvas的api有如下这三个getContext、drawImage、toDataURL,下面来认识一下这三个API。
1、getContext方法
var ctx = canvas.getContext(contextType, contextAttributes);| 参数值 | 含义 |
| 2d | 创建 CanvasRenderingContext2D 二维渲染上下文,像图片这种二维空间的选这个类型。 |
| webgl/experimental-webgl | 创建 WebGLRenderingContext 三维渲染上下文对象,适用于三维动画制作开发。 |
| webgl2/experimental-webgl2 | 创建一个 WebGL2RenderingContext 三维渲染上下文对象,webgl的升级版本。 |
| bitmaprenderer | 将创建将canvas内容替换为指定ImageBitmap功能的ImageBitmapRenderingContext,canvas与位图的生成,笔者也没接触过。 |
2、drawImage方法
drawImage方法是上面getContext获取的上下文里的方法,但是它只在contextType为2d的时候才可以被调用,也就是只能在二维图片的时候使用,可以根据其调用入参控制进行画图、组合图、剪切图。
void ctx.drawImage(image, x, y);在画布上将image图像定位到x坐标长度与y坐标长度,画上去的图片大小就是图片本身的大小,不能控制。
void ctx.drawImage(image, x, y, width, height);在画布上将image图像定位到x坐标长度与y坐标长度,并且指定image图像宽与高。
void ctx.drawImage(image, x, y, width, height, dx, dy, dWidth, dHeight);在画布上将image图像定位到x坐标长度与y坐标长度,并且指定image图像宽与高,然后截取出来,放在(dx,dy)的坐标处,并且指定宽高,感觉可以很快做个文字放大镜。
3、toDataURL方法
canvas.toDataURL(type, encoderOptions);toDataURL方法也是HTMLCanvasElement元素提供的方法,当调用HTMLCanvasElement.toDataURL() 方法时,会返回一个包含图片展示的data URL,像这样的格式data:[<mediatype>][;base64],<data>。
该方法可以接受两个参数。
type: 生成dataURL类型,默认是image/png的的类型,如果需要生成jpg或者其他类型传入即可。
encoderOptions:可选参数,生成的dataURL质量参数,默认是0.92,可以传入0-1之间的小数,越大质量越高,生成的串信息也越多,越长。
三、实现流程
1、生成画布
先生成一块canvas画布,并且把第一张图,一般是背景图画进画布里。这里要注意,drawImage方法的第一个参数是HTMLImageElement元素,你可以通过document.querySelector获取页面上img标签元素,也可以通过createElement('img')去生成,取决于你的图是否在页面上展示着。
// html
<img id="img" />
// javascript
class Canvas {
// 创建canvas
constructor (config = {}) {
this.canvas = document.createElement('canvas');
this.canvas.width = config.bgWidth;
this.canvas.height = config.bgHeight;
this.ctx = this.canvas.getContext('2d');
}
// 画图到画布上
async run(config) {
// images是HTMLImageElement元素,而非链接地址
const image = await getImage(config.src);
this.ctx.drawImage(image, config.x, config.y, config.width, config.height);
}
// 验证使用,将生产的图呈现到页面上
print() {
document.querySelector('#img').setAttribute('src', this.canvas.toDataURL());
}
}
// 调用
const mycanvas = new Canvas({
bgWidth: 500,
bgHeight: 600
})
mycanvas.run({
src: 'https://n.sinaimg.cn/ent/transform/460/w630h630/20180824/Zaob-hicsiaw3749625.jpg',
x: 0,
y: 0,
width: 250,
height: 600
}).then(() => {
// 画到页面上
mycanvas.print()
})2、组装
在同一个ctx上进行两次将两张图进行合并drawImage,进行合并完成。
// html<img id="img" />
// javascript
// canvas合成操作
class Canvas {
...
async run2(img1, img2) {
const images = [img1, img2];
const imgSrcs = images.map(({ src }) => getImage(src));
const imgEles = await Promise.all(imgSrcs);
imgEles.map((ele, i) => {
if (ele) {
const { x = 0, y = 0, width = 0, height = 0 } = images[i];
this.ctx.drawImage(ele, x, y, width, height);
}
});
}
...
}
// 调用
const mycanvas = new Canvas({
bgWidth: 500,
bgHeight: 600
})
mycanvas.run({
src: 'https://n.sinaimg.cn/ent/transform/460/w630h630/20180824/Zaob-hicsiaw3749625.jpg',
x: 0,
y: 0,
width: 250,
height: 600
}, {
src: 'https://n.sinaimg.cn/ent/transform/460/w630h630/20180824/Zaob-hicsiaw3749625.jpg',
x: 250,
y: 0,
width: 250,
height: 600
}).then(() => {
// 画到页面上
mycanvas.print()
})3、调用结果如下
4、实现下载方法
class Canvas {
...
download() {
// 文件流式下载
this.canvas.toBlob(blob => {
const a = document.createElement('a');
a.download = 'image.png';
a.style.display = 'none';
a.href = URL.createObjectURL(blob);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}
...
}四、发布至NPM,开源共享
目前我已经将上述组合图片的功能做成了开源package,上传至npm源上,如果有有需要的可以使用以下命令直接使用。
npm包地址https://www.npmjs.com/package/composite-image
issue地址
https://github.com/FantasyGao/composite-image/issues
// 直接安装使用npm/cnpm i --save composite-image
// 也可以在html文件直接引入
<script src='node_module/composite-image/composite-image.js'></script>欢迎各位使用与提一些建议,感谢。
招聘
前端工程师:
2 年以上工作经验,本科及以上学历。
具备良好的 HTML/CSS/JS 前端基础,有 react / vue 等主流框架开发经验,并深入理解其原理,熟悉 webpack,Rollup打包工具 。
对互联网产品和 Web 技术有浓厚兴趣,有强大的自我驱动能力、学习能力和强烈的进取心。
计算机网络基础知识具备良好基础。
(加分)有服务端的开发经验。
(加分)需熟练掌握移动端 H5 / hybrid 开发;
(加分)对移动前端性能优化有充足的实践和方法;
(加分)熟悉小程序开发经历。
(加分)熟悉 node.js 异步编程,了解nodejs基本运行原理。
(加分)有金融基础知识,了解支付领域相关技术更佳。
JAVA工程师(金融领域)
参与研发蚂蚁新型金融产品,与现有数字金融各板块整合,打造更加灵活、普惠的支付生活体验;
参与相关应用、功能模块的设计和研发实现;
能够用创新的方式,解决上述领域的技术或业务难题。
具备3年以上大中型互联网公司分布式系统的研发经验;
有前端能技能更佳;
思路清晰敏捷,沟通协调能力及决断能力强。
有创业精神,能在面临较多不确定性和变化的环境中,始终保持工作激情和责任心。
实习生