背景
最近接手一个任务,大致要求就是可以动态合成图片。
没听懂?那我再解释下:
大致就是如上功能。
这个时候,会的,或者稍微会的,或者真的会的,就开会七嘴八舌了:吧唧吧唧....
前端的孩子开始发言了:这个不是很简单吗?使用canvas来合成图片不就可以了吗?
后端的孩子额头紧锁,半天不说话,似乎在酝酿什么!
过了半天,后端孩子开始说话了,canvas合成的,效果比较单一,要合成比较复杂的海报,能力有限!
前端的孩子开始不开心了:你会,那你说说看,怎么实现?
后端开始稳重的说话!
合成图片方案1:前端canvas
这种方案的优点,就是动作在前端就可以直接完成,但是缺点就是灵活性欠缺,针对部分比较多变的海报,或者特效比较好的广告,没办法把我们想要的效果简单的体现出来。另外一个缺点是兼容性比较差,对于客户端,尤其是iphone适配能力没那么强。所以这种方式只能针对部分比较简单的场景使用!
结论
pass
合成图片方案2:服务端jCharts
jCharts是一款基于Java的图表绘制类库,jCharts包含了多种图表格式,包括线型图、饼图、柱形图和点图等。
比如下面就是基于jCharts在服务端生成的图表:
它的官网是:jCharts官网
但是这种方式同样的适配能力有限,只能在图表方面大展拳脚,如果想生成其他的图片就无能为力了!
结论
pass
合成图片方案3:服务端gm
gm是GraphicsMagic的依赖包,可以进行丰富的图片处理。能力也非常强大,图片裁剪合成样样精通,基本上你能想象的到的功能都能实现。但是跟canvas一样,同样面临一个问题,那就是对于复杂的特效,实现能力有限。注意,特效,已经不是指对已有图片的处理了!而是指如何去无中生有实现好看的图片。
同时gm的使用依赖其他的软件:GraphicsMagic。这个软件同样需要安装。
所以同样会有平台的兼容性的问题。
GraphicsMagic 官网是: http://www.graphicsmagick.org/
结论
pass
合成图片方案4:服务端phantom
phantom是一个比较牛逼的库了。支持多种语言。
PhantomJS简介:
(1)一个基于webkit内核的无头浏览器,即没有UI界面,即它就是一个浏览器,只是其内的点击、翻页等人为相关操作需要程序设计实现。
(2)提供javascript API接口,即通过编写js程序可以直接与webkit内核交互,在此之上可以结合java语言等,通过java调用js等相关操作,从而解决了以前c/c++才能比较好的基于webkit开发优质采集器的限制。
(3)提供windows、linux、mac等不同os的安装使用包,也就是说可以在不同平台上二次开发采集项目或是自动项目测试等工作。
目前笔者这边使用过的有在python环境,有在node环境。
实现方式
phantom怎么实现图片合成呢!其实就是利用截图来实现的!
phantom的官网:https://phantomjs.org/
下面简单来介绍下如何利用phantom来截图:
在看下面内容之前建议先看完基础课
1、phantom截图方式1-截图在线网页:
var phantom = require('phantom');
let start = Date.now()
phantom.create().then(function(ph) {ph.createPage().then(function(page) {page.open("http://www.baidu.com").then(function(status) {// page.property('viewportSize', { width: 375, height: 667 });// 设置截图的大小page.render('./baidu.jpg').then(function() {console.log('Page rendered');ph.exit();console.log(Date.now() - start)});});});
});
2、phantom截图方式2-截图动态html字符串:
var phantom = require('phantom');
let start = Date.now()
phantom.create().then(function(ph) {ph.createPage().then(function(page) {page.property('content', '<html style="background-color: red"><h1>测试一下</h1></html>')// 设置html字符串page.render('./baidu.jpg').then(function () {console.log('Page rendered');ph.exit();});})
});
效果这边就不演示了。优点大家已经看到了,就是支持灵活多变的图片合成,所有的效果,可以实现通过html编排好。然后去截图,就可以了。但是比较致命的缺点是:合成的图片的清晰度非常低,如果对清晰度没有要求的倒是可以使用。另外一个缺点就是合成速度偏慢!
因为是海报和广告制作,所以显然phantom也是不符合要求的
结论
pass
合成图片方案5:服务端puppeteer
Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包,用来模拟 Chrome 浏览器的运行。相比于phantom而言,更推荐puppeteer(主要是因为 PhantomJs 坑太多了)。这边简单介绍下puppeteer的作用,后续会更新系列puppeteer的文章。puppeteer可以用来合成图片(实现原理也是截图,但是可以支持高清截图,而且截图速度快),可以用来做自动化测试等。下面引用其他的一些总结:
Puppeteer 是什么
Puppeteer 是 Node.js 工具引擎
Puppeteer 提供了一系列 API,通过 Chrome DevTools Protocol 协议控制 Chromium/Chrome 浏览器的行为
Puppeteer 默认情况下是以 headless 启动 Chrome 的,也可以通过参数控制启动有界面的 Chrome
Puppeteer 默认绑定最新的 Chromium 版本,也可以自己设置不同版本的绑定
Puppeteer 让我们不需要了解太多的底层 CDP 协议实现与浏览器的通信
Puppeteer 能做什么
官方称:“Most things that you can do manually in the browser can be done using Puppeteer”,那么具体可以做些什么呢?
网页截图或者生成 PDF
爬取 SPA 或 SSR 网站
UI 自动化测试,模拟表单提交,键盘输入,点击等行为
捕获网站的时间线,帮助诊断性能问题
创建一个最新的自动化测试环境,使用最新的 js 和最新的 Chrome 浏览器运行测试用例
测试 Chrome 扩展程序
实现方式
puppeteer官网:https://github.com/puppeteer/puppeteer
puppeteer核心文档:https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md#pagescreenshotoptions
下面简单分享下,puppeteer实现截图两种方式:
1、puppeteer截图方式1-截图在线网页
const puppeteer = require('puppeteer');
(async () => {let start = Date.now()const browser = await puppeteer.launch();const page = await browser.newPage();await page.emulate(puppeteer.devices['iPhone X']);// 使用iphonex模式来进行高分屏截图await page.goto("http://www.baidu.com");await page.screenshot({path: `./jd-${1}.png`,// 注意:png清晰度远胜于jpg});console.log(Date.now() - start)await browser.close();
})();
2、puppeteer截图方式2-截图动态html字符串
const puppeteer = require('puppeteer');
(async () => {let start = Date.now()const browser = await puppeteer.launch();const page = await browser.newPage();await page.emulate(puppeteer.devices['iPhone X']);await page.setContent('<h1>测试下咯</h1>')await page.screenshot({path: `./jd-${1}.png`,// 注意:png清晰度远胜于jpg});console.log(Date.now() - start)await browser.close();
})();
效果,刚刚也说了,非常的赞!满足此次要求。
结论
通过!